纳税服务系统五(登陆与系统拦截)【配置系统、子系统首页、登陆与拦截】...

 
 

前言

到目前位置,我们的用户模块和角色模块基本已经做好了,我们的纳税服务系统是放在一个大系统里边的。我们应该把我们已经写好的模块加载进去

本文主要的知识点:

加载整个系统首页

导入对应的JSP页面:

640?wx_fmt=png
这里写图片描述

创建home模块的包,对应的Action和struts配置文件

640?wx_fmt=png
这里写图片描述

效果图:

640?wx_fmt=png
这里写图片描述

把纳税服务系统加到总系统上

当我点击纳税服务的时候,会出现纳税服务子系统的页面

640?wx_fmt=png
这里写图片描述

绑定相关的超链接,跳转到对应的Action中

    <li><a href="${ctx }/nsfw/home_frame.action">纳税服务</a> </li>    <a href="${ctx }/nsfw/home_frame.action">纳税服务</a> </li>    

导入对应的JSP页面:

640?wx_fmt=png
这里写图片描述

创建对应的模块包和配置文件:

640?wx_fmt=png
这里写图片描述
public class HomeAction {    public String frame() {        return "frame";    }    public String left() {        return "left";    }    public String top() {        return "top";    }}class HomeAction {

   public String frame() {
       return "frame";
   }
   public String left() {
       return "left";
   }
   public String top() {
       return "top";
   }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"        "http://struts.apache.org/dtds/struts-2.3.dtd"><struts>    <package name="nsfw-home" namespace="/nsfw" extends="struts-default">        <action name="nsfw_*" class="zhongfucheng.nsfw.HomeAction" method="{1}">            <result name="{1}">/WEB-INF/jsp/nsfw/{1}.jsp</result>        </action>    </package></struts>

<!DOCTYPE struts PUBLIC
       "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
       "http://struts.apache.org/dtds/struts-2.3.dtd">


<struts>
   <package name="nsfw-home" namespace="/nsfw" extends="struts-default">

       <action name="nsfw_*" class="zhongfucheng.nsfw.HomeAction" method="{1}">
           <result name="{1}">/WEB-INF/jsp/nsfw/{1}.jsp</result>
       </action>
   </package>
</struts>
640?wx_fmt=png
这里写图片描述

子功能添加到纳税服务系统中

就是让左边的导航栏跳转到我们的对应显示页面就行了

    <dl class="">        <dt><a class="yh" href="${basePath}role/role_listUI.action" target="mainFrame"><b></b>角色管理<s class="down"></s>        </a></dt>    </dl>    <dl class="">        <dt><a class="yh" href="${basePath}user/user_listUI.action" target="mainFrame"><b></b>用户管理<s class="down"></s>        </a></dt>    </dl>
       <dt><a class="yh" href="${basePath}role/role_listUI.action" target="mainFrame"><b></b>角色管理<s class="down"></s>
       </a></dt>
   </dl>
   <dl class="">
       <dt><a class="yh" href="${basePath}user/user_listUI.action" target="mainFrame"><b></b>用户管理<s class="down"></s>
       </a></dt>
   </dl>



到目前为止,我们已经写了用户模块和角色模块了。也已经把系统的首页和子系统的首页配置好了。我们的系统是需要登陆后才能访问的

640?wx_fmt=png
这里写图片描述

因此,接下来主要讲解登陆模块、权限拦截


登陆模块

编写Action与配置文件

引入对应的JSP页面

640?wx_fmt=png
这里写图片描述

编写Action处理请求和对应的配置文件:

640?wx_fmt=png
这里写图片描述

效果:

640?wx_fmt=png
这里写图片描述

Action处理

在常量类中保存着一个Session的标识:

    /***********保存Session域的常量***********/    public static String USER = "SYS_USER";
   public static String USER = "SYS_USER";

Action

package zhongfucheng.login;import com.opensymphony.xwork2.ActionContext;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.factory.annotation.Autowired;import zhongfucheng.core.action.BaseAction;import zhongfucheng.core.constant.Constant;import zhongfucheng.user.entity.User;import zhongfucheng.user.service.UserService;import java.util.List;/** * Created by ozc on 2017/6/2. */public class LoginAction extends BaseAction {    /***************封装数据**********************/    private User user;    public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }    /****************调用userService****************************/    @Autowired    private UserService userServiceImpl;    public String loginUI() {        return "loginUI";    }    /****************记载着登陆状态信息*********************/    private String loginResult;    public String getLoginResult() {        return loginResult;    }    public void setLoginResult(String loginResult) {        this.loginResult = loginResult;    }    /*****************业务方法******************/    public String login() {        if (user != null) {            List<User> list = userServiceImpl.findUserByAccountAndPassword(user.getAccount(), user.getPassword());            //如果查到有值,那么就证明有该用户的,给他登陆            if (list != null && list.size() > 0) {                //保存到Session域中,为了更方便用,我们使用常量保存。                ActionContext.getContext().getSession().put(Constant.USER, list.get(0));                //保存到日志文件中Log                Log log = LogFactory.getLog(getClass());                log.info("用户名称为" + list.get(0).getName() + "登陆了系统!");                //重定向到首页                return "home";            } else {                //登陆失败,记载登陆信息                loginResult = "登陆失败了,用户名或密码错误了";            }        }        //只要不成功的,都回到登陆页面        return loginUI();    }}

import com.opensymphony.xwork2.ActionContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import zhongfucheng.core.action.BaseAction;
import zhongfucheng.core.constant.Constant;
import zhongfucheng.user.entity.User;
import zhongfucheng.user.service.UserService;

import java.util.List;

/**
* Created by ozc on 2017/6/2.
*/

public class LoginAction extends BaseAction {

   /***************封装数据**********************/
   private User user;
   public User getUser() {
       return user;
   }
   public void setUser(User user) {
       this.user = user;
   }
   /****************调用userService****************************/
   @Autowired
   private UserService userServiceImpl;

   public String loginUI() {
       return "loginUI";
   }

   /****************记载着登陆状态信息*********************/
   private String loginResult;

   public String getLoginResult() {
       return loginResult;
   }

   public void setLoginResult(String loginResult) {
       this.loginResult = loginResult;
   }

   /*****************业务方法******************/

   public String login() {

       if (user != null) {
           List<User> list = userServiceImpl.findUserByAccountAndPassword(user.getAccount(), user.getPassword());

           //如果查到有值,那么就证明有该用户的,给他登陆
           if (list != null && list.size() > 0) {

               //保存到Session域中,为了更方便用,我们使用常量保存。
               ActionContext.getContext().getSession().put(Constant.USER, list.get(0));

               //保存到日志文件中Log
               Log log = LogFactory.getLog(getClass());
               log.info("用户名称为" + list.get(0).getName() + "登陆了系统!");

               //重定向到首页
               return "home";
           } else {
               //登陆失败,记载登陆信息
               loginResult = "登陆失败了,用户名或密码错误了";
           }
       }
       //只要不成功的,都回到登陆页面
       return loginUI();
   }
}

在dao层中实现根据账户和密码查询数据:

    @Override    public List<User> findUserByAccountAndPassword(String account, String password) {        //通过账户和密码查找对象        String sql = "FROM User WHERE account=? AND password=?";        return getSession().createQuery(sql).setParameter(0, account).setParameter(1,password).list();    }
   public List<User> findUserByAccountAndPassword(String account, String password) {

       //通过账户和密码查找对象
       String sql = "FROM User WHERE account=? AND password=?";
       return getSession().createQuery(sql).setParameter(0, account).setParameter(1,password).list();


   }

我们还在Action中定义了一个String来记载着Login的状态,如果出错了。我们就返回loginUI界面,然后在那里回显Login出错的信息。

同时登录完在系统主页上回显数据:

    <a><b></b><font color="red">欢迎您,<s:property value="%{#session.SYS_USER.account}"/> &nbsp;</font></a><b></b><font color="red">欢迎您,<s:property value="%{#session.SYS_USER.account}"/> &nbsp;</font></a>
640?wx_fmt=png
这里写图片描述

注销功能

在主页上的退出上绑定超链接

    <td align="left" valign="middle" ><a href="${ctx}/sys/login_logout.action">退出</a></td><a href="${ctx}/sys/login_logout.action">退出</a></td>

Action处理:

    public String logout() {        //销毁session的值        ActionContext.getContext().getSession().remove(Constant.USER);        return loginUI();    }

       //销毁session的值
       ActionContext.getContext().getSession().remove(Constant.USER);

       return loginUI();
   }

处理首页

当用户访问首页的时候,我们重定向到登陆页面:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%  String path = request.getContextPath();  String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  response.sendRedirect(basePath + "sys/login_loginUI.action");%>import="java.util.*" pageEncoding="utf-8"%>
<%
 String path = request.getContextPath();
 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 response.sendRedirect(basePath + "sys/login_loginUI.action");
%>

过滤器模块

进入系统拦截

我们讲道理是要用户登陆后,才能访问我们的总系统。但是现在假如用户知道了我们的首页地址,他可以直接访问我们的首页地址而不用登陆。这是不合适的。

640?wx_fmt=png


因此,我们写一个过滤器进行拦截,如果用户不是想要登陆,而访问我们其他的页面。都拦截他,让他登陆后才能访问。

640?wx_fmt=png
这里写图片描述

过滤器:

package zhongfucheng.core.filter;import zhongfucheng.user.entity.User;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Created by ozc on 2017/6/4. */public class LoginFilter implements Filter {    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) resp;        //得到用户访问的路径        String uri = request.getRequestURI();        //登陆路径        String loginPath = request.getContextPath() + "/sys/login_login.action";        //判断用户访问的是哪里        if (!uri.contains("login_")) {//如果不是访问我们的登陆模块            //判断该用户是否登陆了。            User user = (User) request.getSession().getAttribute("SYS_USER");            if (user == null) {//如果在session找不到,那么就是没有登陆                //没有登陆,跳转到登陆页面                response.sendRedirect(loginPath);                return;            } else {//有用户信息,就是登陆了。                //放行                chain.doFilter(request, response);            }        } else {//如果是访问我们的登陆模块,放行            chain.doFilter(request, response);        }    }    public void init(FilterConfig config) throws ServletException {    }    public void destroy() {    }}

import zhongfucheng.user.entity.User;

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

/**
* Created by ozc on 2017/6/4.
*/


public class LoginFilter implements Filter {

   public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
       HttpServletRequest request = (HttpServletRequest) req;
       HttpServletResponse response = (HttpServletResponse) resp;

       //得到用户访问的路径
       String uri = request.getRequestURI();

       //登陆路径
       String loginPath = request.getContextPath() + "/sys/login_login.action";

       //判断用户访问的是哪里
       if (!uri.contains("login_")) {//如果不是访问我们的登陆模块

           //判断该用户是否登陆了。
           User user = (User) request.getSession().getAttribute("SYS_USER");

           if (user == null) {//如果在session找不到,那么就是没有登陆
               //没有登陆,跳转到登陆页面
               response.sendRedirect(loginPath);
               return;

           } else {//有用户信息,就是登陆了。

               //放行
               chain.doFilter(request, response);
           }

       } else {//如果是访问我们的登陆模块,放行
           chain.doFilter(request, response);
       }
   }

   public void init(FilterConfig config) throws ServletException {

   }

   public void destroy() {
   }
}

配置过滤器,需要在struts过滤器之前配置:

    <filter>        <filter-name>LoginFilter</filter-name>        <filter-class>zhongfucheng.core.filter.LoginFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>LoginFilter</filter-name>        <url-pattern>*.action</url-pattern>    </filter-mapping>
       <filter-name>LoginFilter</filter-name>
       <filter-class>zhongfucheng.core.filter.LoginFilter</filter-class>
   </filter>
   <filter-mapping>
       <filter-name>LoginFilter</filter-name>
       <url-pattern>*.action</url-pattern>
   </filter-mapping>


权限过滤

我们的纳税服务子系统并不是任何人都可以进去操作的,我们有可以对角色的管理,对用户的管理。。一般的用户是没有权限去操作这些东西的。因此,我们要对其进行权限控制。

当该用户有权限才能够访问纳税服务系统的内容,没有权限就不给该用户看。

权限过滤的前提条件:

由于我们在LoginFilter中已经可以得到这两个条件了,于是我们在LoginFilter中接着写就行了。又因为权限过滤是一个比较单独的模块,我们可以将其抽出。这样一来,LoginFilter又不会显得太大,职责又分工了。

640?wx_fmt=png
这里写图片描述

过滤器全部代码:WebApplicationContextUtils得到IOC中的对象

package zhongfucheng.core.filter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;import zhongfucheng.core.utils.PermissionCheck;import zhongfucheng.user.entity.User;import zhongfucheng.user.service.UserService;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Created by ozc on 2017/6/4. */public class LoginFilter implements Filter {    //注入userService    @Autowired    private UserService userServiceImpl;    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) resp;        //得到用户访问的路径        String uri = request.getRequestURI();        //登陆路径        String loginPath = request.getContextPath() + "/sys/login_login.action";        //提示页面        String warningPath = request.getContextPath() + "/sys/login_noPermissionUI.action";        //定义User变量        User user;        //判断用户访问的是哪里        if (!uri.contains("login_")) {//如果不是访问我们的登陆模块            //判断该用户是否登陆了。             user = (User) request.getSession().getAttribute("SYS_USER");            if (user == null) {//如果在session找不到,那么就是没有登陆                //没有登陆,跳转到登陆页面                response.sendRedirect(loginPath);                return;            } else {//有用户信息,就是登陆了。                if (uri.contains("nsfw")) {//如果访问纳税服务系统,就要有对应的权限                    //用户已经登陆了,判断用户有没有权限访问子系统                    //得到IOC容器中的对象                    WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());                    PermissionCheck permissionCheck = (PermissionCheck)applicationContext.getBean("permissionCheck");                    if (permissionCheck.check(user, "nsfw")) {//有权限                        //放行                        chain.doFilter(request, response);                    } else {//没有权限                        //返回到提示页面                        response.sendRedirect(warningPath);                    }                } else {//可以不用权限,直接放行                    //放行                    chain.doFilter(request, response);                }            }        } else {//如果是访问我们的登陆模块,放行            chain.doFilter(request, response);        }    }    public void init(FilterConfig config) throws ServletException {    }    public void destroy() {    }}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import zhongfucheng.core.utils.PermissionCheck;
import zhongfucheng.user.entity.User;
import zhongfucheng.user.service.UserService;

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

/**
* Created by ozc on 2017/6/4.
*/


public class LoginFilter implements Filter {

   //注入userService
   @Autowired
   private UserService userServiceImpl;

   public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
       HttpServletRequest request = (HttpServletRequest) req;
       HttpServletResponse response = (HttpServletResponse) resp;

       //得到用户访问的路径
       String uri = request.getRequestURI();

       //登陆路径
       String loginPath = request.getContextPath() + "/sys/login_login.action";

       //提示页面
       String warningPath = request.getContextPath() + "/sys/login_noPermissionUI.action";

       //定义User变量
       User user;
       //判断用户访问的是哪里
       if (!uri.contains("login_")) {//如果不是访问我们的登陆模块

           //判断该用户是否登陆了。
            user = (User) request.getSession().getAttribute("SYS_USER");
           if (user == null) {//如果在session找不到,那么就是没有登陆
               //没有登陆,跳转到登陆页面
               response.sendRedirect(loginPath);
               return;

           } else {//有用户信息,就是登陆了。

               if (uri.contains("nsfw")) {//如果访问纳税服务系统,就要有对应的权限

                   //用户已经登陆了,判断用户有没有权限访问子系统

                   //得到IOC容器中的对象
                   WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
                   PermissionCheck permissionCheck = (PermissionCheck)applicationContext.getBean("permissionCheck");

                   if (permissionCheck.check(user, "nsfw")) {//有权限
                       //放行
                       chain.doFilter(request, response);
                   } else {//没有权限

                       //返回到提示页面
                       response.sendRedirect(warningPath);
                   }

               } else {//可以不用权限,直接放行
                   //放行
                   chain.doFilter(request, response);
               }
           }

       } else {//如果是访问我们的登陆模块,放行
           chain.doFilter(request, response);
       }
   }

   public void init(FilterConfig config) throws ServletException {

   }

   public void destroy() {
   }


}

在登陆完之后,就查询出用户拥有的所有角色,并设置到该用户中:

    public String login() {        if (user != null) {            List<User> list = userServiceImpl.findUserByAccountAndPassword(user.getAccount(), user.getPassword());            //如果查到有值,那么就证明有该用户的,给他登陆            if (list != null && list.size() > 0) {                //查出用户所有的权限,设置到User中                User user = list.get(0);                List<UserRole> roles = userServiceImpl.findRoleById(user.getId());                user.setUserRoles(roles);                //保存到Session域中,为了更方便用,我们使用常量保存。                ActionContext.getContext().getSession().put(Constant.USER, user);                //保存到日志文件中Log                Log log = LogFactory.getLog(getClass());                log.info("用户名称为" + list.get(0).getName() + "登陆了系统!");                //重定向到首页                return "home";            } else {                //登陆失败,记载登陆信息                loginResult = "登陆失败了,用户名或密码错误了";            }        }        //只要不成功的,都回到登陆页面        return loginUI();    }

       if (user != null) {
           List<User> list = userServiceImpl.findUserByAccountAndPassword(user.getAccount(), user.getPassword());

           //如果查到有值,那么就证明有该用户的,给他登陆
           if (list != null && list.size() > 0) {

               //查出用户所有的权限,设置到User中
               User user = list.get(0);
               List<UserRole> roles = userServiceImpl.findRoleById(user.getId());
               user.setUserRoles(roles);

               //保存到Session域中,为了更方便用,我们使用常量保存。
               ActionContext.getContext().getSession().put(Constant.USER, user);


               //保存到日志文件中Log
               Log log = LogFactory.getLog(getClass());
               log.info("用户名称为" + list.get(0).getName() + "登陆了系统!");

               //重定向到首页
               return "home";
           } else {
               //登陆失败,记载登陆信息
               loginResult = "登陆失败了,用户名或密码错误了";
           }
       }
       //只要不成功的,都回到登陆页面
       return loginUI();
   }

在User.java中加入一个List集合,存储着用户所拥有的角色

    //得到用户所有的角色    private List<UserRole> userRoles;    public List<UserRole> getUserRoles() {        return userRoles;    }    public void setUserRoles(List<UserRole> userRoles) {        this.userRoles = userRoles;    }
   private List<UserRole> userRoles;
   public List<UserRole> getUserRoles() {
       return userRoles;
   }
   public void setUserRoles(List<UserRole> userRoles) {
       this.userRoles = userRoles;
   }

到这里,有同学可能会疑问,为啥现在我要修改User的结构呢??明明在编写User和Role的时候说好不修改User类的。我们在验证的时候需要得到用户所有的角色,从而得到权限。如果在检查的时候做的话,我们用的是过滤器检查,每请求一次都要去访问数据库。

这样的话就非常耗费我们的性能,于是我们就修改User类,但这次的修改没有影响到我们其他地方的操作。这样一来,我们在检查的时候就可以通过对象来得到用户对应的权限了,不用查询数据库。

检查用户是否有权限:

public class PermissionCheck {    private User user;    private String code;    @Autowired    private UserService userServiceImpl;    public boolean check(User user, String code) {        this.user = user;        this.code = code;        //得到该用户的所有权限        List<UserRole> userRoles = user.getUserRoles();        if (userRoles == null) {            userRoles = userServiceImpl.findRoleById(user.getId());        }        //遍历初用户拥有的角色,看看有没有对应的权限        for (UserRole userRole : userRoles) {            Role role = userRole.getUserRoleId().getRole();            //得到角色所拥有的权限            Set<RolePrivilege> rolePrivilegeSet = role.getRolePrivilegeSet();            //遍历权限,看看有没有nsfw的权限            for (RolePrivilege privilege : rolePrivilegeSet) {                String code1 = privilege.getCompositeKey().getCode();                if (code1.equals(code)) {//如果该用户有权限                    return true;                }            }        }        //遍历完都没有return true,那么就是没有权限了。        return false;    }}class PermissionCheck {

   private User user;
   private String code;

   @Autowired
   private UserService userServiceImpl;


   public boolean check(User user, String code) {
       this.user = user;
       this.code = code;

       //得到该用户的所有权限
       List<UserRole> userRoles = user.getUserRoles();

       if (userRoles == null) {
           userRoles = userServiceImpl.findRoleById(user.getId());
       }

       //遍历初用户拥有的角色,看看有没有对应的权限
       for (UserRole userRole : userRoles) {
           Role role = userRole.getUserRoleId().getRole();

           //得到角色所拥有的权限
           Set<RolePrivilege> rolePrivilegeSet = role.getRolePrivilegeSet();

           //遍历权限,看看有没有nsfw的权限
           for (RolePrivilege privilege : rolePrivilegeSet) {
               String code1 = privilege.getCompositeKey().getCode();
               if (code1.equals(code)) {//如果该用户有权限
                   return true;
               }
           }
       }
       //遍历完都没有return true,那么就是没有权限了。
       return false;
   }
}

页面嵌套问题

现在我打开了两个首页,是同一个会话的。如果用户太久没有操作我们的页面,那么Session就会被摧毁。

640?wx_fmt=png
这里写图片描述

等用户再操作的时候,Session已经被Tomcat摧毁了。讲道理用户操作页面的时候,是会回到登陆页面的。我们看看发生了什么:

640?wx_fmt=png
这里写图片描述

登陆页面嵌套在我们右边的显示页面了。为啥出现这种情况??

所以,到目前为止,我们的逻辑是没毛病的。但怎么解决上面遇到的情况呢??** 我们不需要使用监听器Session,监听Session被摧毁了,然后刷新页面**。。我们用更好地一种解决办法:

    /*如果该页面不是顶级窗口,那么就自动刷新一下到父窗口中*/    if(window!=window.parent) {        window.parent.location.reload(true);    }
   if(window!=window.parent) {
       window.parent.location.reload(true);
   }

总结

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值