Maven项目学习(一)搭建SSM项目及启动,并进行ajax提交信息进行登录系统操作到主页面(详细)

2020年4月补:

①:看着1月份自己写的代码有点看不下去了,而且之前提交数据没有用到ajax,前端没有用到框架,看着有点想吐。因为看这篇文章的伙伴大部分是新手吧(目前有个小伙伴收藏了这篇文章),出于好意,我还是要改改控制器和前端的代码,不要“误人子弟”(之前的代码没错,但不希望有人跟着之前我写的代码写),修改的内容在页面最后,有兴趣可以对比一下代码。

②:这里的spring-web.xml文件的事务配置是比较粗略的,你有兴趣还是要学一下,因为事务和AOP是很重要的。

③:前端提交数据用到了js、JQuery和前端框架layui。

 

1.打开IDEA,创建Maven项目。

打开IDEA,选择新建项目,这里选择maven选项,不选择模板,直接点击Next。

填写GroupId,和ArtifactId,后点Next,然后点击Finish。

这里啰嗦一下,GroupId指的是公司名称,ArtifactId指的是项目的名称。

创建完成后,删除src文件夹。

右键点击项目名称myhomes,新建一个用于存放业务层biz资料的module。

新建module界面中依旧不选择模板,直接点击Next。

填写module名称,并点击Next后保存。

 

继续在myhomes新建一个module,这个module用于存放DAO数据库操作类等相关文件。操作步骤跟上一个大致相同,唯一不同的地方是module的名不一样,我这里module名是myhomes_dao。

新建最后一个module,该module用于存放Web层数据的。这里要用到web模板。

之后填写该module的名字保存即可,之后等待IDEA下载模板完成。这里的module名字是myhomes_web。

项目下载完成后,myhomes_web中的src下的main文件夹应该是没有java和resources文件夹的,因此我们需要创建。

创建好后文件夹需要进行“Mark Directory as”操作,该操作指定文件夹是用来放什么资料的。

java文件夹设置成Sources Root

将resources文件夹设置成Resources Root(这就不放图了)

然后在每个module中所需新建文件夹,我这里这里设置如下

2.为各个module的pom.xml文件添加相关依赖

先为myhomes_dao的pom.xml文件添加相关依赖:

<dependencies>
    <!--Mybatis-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.41</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>

    <!--Spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>

    <!--Spring整合Mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.1</version>
    </dependency>
</dependencies>

为myhomes_biz的pom.xml文件添加相关依赖:

<dependencies>
    <!--myhome_biz是业务层,需要依赖持久层,也就是myhome_dao-->
    <dependency>
        <groupId>com.myhome</groupId>
        <artifactId>myhome_dao</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.9</version>
    </dependency>
</dependencies>

为myhomes_web的pom.xml文件添加相关依赖:

pom文件有些位置内容我改动了,不知道跟你创建的那时候这些位置内容是否一样。

pox文件头部的project标签最后那个网址:

<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/maven-4.0.0.xsd">

还有就是下面那个url标签内的网址:

<url>http://maven.apache.org</url>

目前我不知道不改会出现什么问题,这里就提一下。

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>

    <!--导入业务层依赖-->
    <dependency>
        <groupId>com.myhome</groupId>
        <artifactId>myhome_biz</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
    </dependency>
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

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

3.添加xml配置文件

首先为dao层的resources资源文件夹添加xml配置文件spring-dao.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启自动扫描-->
    <context:component-scan base-package="com.myhomes.dao"/>

    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/home?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--配置SessionFactory-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.myhomes.entity"/>
    </bean>

    <!--配置映射扫描器,让mybaits扫描映射文件包-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
        <property name="basePackage" value="com.myhomes.dao"/>
    </bean>

</beans>

 

接着为biz层的resources资源文件夹添加xml配置文件spring-biz.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--声明式事务配置在业务层-->

    <!--导入dao层配置文件-->
    <import resource="spring-dao.xml"/>

    <!--开启自动扫描-->
    <context:component-scan base-package="com.myhomes.biz"/>

    <!--aop自动代理-->
    <aop:aspectj-autoproxy/>

    <!--事务管理器-->
    <bean id="transationManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--声明通知,定义规则-->
    <tx:advice id="txAdvice" transaction-manager="transationManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>   <!--不用事务封装-->
            <tx:method name="find*" read-only="true"/>
            <tx:method name="search*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--通知和切入点进行关联-->
    <aop:config>
        <aop:pointcut id="txpc" expression="execution(* com.myhomes.biz.*.*(..))"/>    <!--第一个*号代表任意返回值-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txpc"/>
    </aop:config>

</beans>

接着为web层的resources资源文件夹添加xml配置文件spring-web.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--导入biz层配置文件-->
    <import resource="spring-biz.xml"/>

    <!--开启自动扫描-->
    <context:component-scan base-package="com.myhomes.controller"/>

    <!--配置mvc自动驱动-->
    <mvc:annotation-driven/>

    <!--静态资源交给servlet处理-->
    <mvc:default-servlet-handler/>


    <!--视图转换器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.myhomes.global.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

紧接着在web层中的web.xml文件进行配置:(这里的编码过滤器的类是自己创建的)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!--处理中文乱码-->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>com.myhomes.global.EncodingFilter</filter-class><!--自己创建的类-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/assets/*</url-pattern>
        <url-pattern>/js/*</url-pattern>
        <url-pattern>/css/*</url-pattern>
        <url-pattern>/img/*</url-pattern>
        <url-pattern>/vendor/*</url-pattern>
        <url-pattern>*.js</url-pattern>
        <url-pattern>*.jpg</url-pattern>
        <url-pattern>*.gif</url-pattern>
        <url-pattern>*.png</url-pattern>
        <url-pattern>*.css</url-pattern>
        <url-pattern>*.ico</url-pattern>
    </servlet-mapping>

    <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:spring-web.xml</param-value>
        </init-param>
        <!--让项目启动的时候自动加载-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>


</web-app>

EncodingFilter类:

package com.myhomes.global;

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

public class EncodingFilter implements Filter {
    private String encoding = "utf-8";
    public void init(FilterConfig filterConfig) throws ServletException {
        if(filterConfig.getInitParameter("encoding")!=null){
            encoding = filterConfig.getInitParameter("encoding");
        }
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        filterChain.doFilter(request,response);
    }

    public void destroy() {
    }
}

新建项目资源文件夹:

项目页面文件放在WEB-INF下的pages里面,这跟spring-web.xml文件里的视图解析器的前缀一致。

4.准备数据库文件

这里的数据库是用MySQL的,并且使用Navicat of MySQL对数据库进行管理。

数据库文件内容如下:

数据库名称:home

数据表:users        及其列名类型等,user_class是该表的外键,这个列指的是用户的类型!

(为什么要使用外键?直接将user_class列的内容直接设置成类型名不好吗(例如设置成“普通用户”)?针对这个问题,我想说的是:如果这张表有1万条普通用户数据,则这1万条数据的user_class列都设置成“普通用户”,有1万条“普通用户”的字符串。如果将user_class列设置成外键,把此列设置成数字,比如1代表普通用户。则1万条数据此列的内容为“1”,减少了数据的臃肿。添加一张用户类型表,表有两个列,id和name。id就设置成1,对应普通用户的user_class列的值1,name属性设置成“普通用户”即可。)

users表的内容:

 

数据表user_class:

user_class表的内容:

5.dao层内容

在entity包中新建实体类User,对应数据库users表的列,并且自动生成getter和setter(按Alt + Insert)。注意,有些属性名跟数据库对应的列的名字不一样,例如userClass属性对应的是user_class列。

在dao包中新建UserDao接口类型的类。

在类的前面添加注解@Repository,告诉Spring这个类是dao层(数据库操作)的类;

在类中添加相应的方法;

在dao层的resources的文件夹中新建一个目录,此目录的路径是:com\myhomes\dao,此路径与spring-dao.xml文件的映射扫描器的basePackage的路径一致。

创建名为UserDao的xml文件:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.4//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.myhomes.dao.UserDao">
    <resultMap id="resultMap" type="User">
        <id property="id" column="id" javaType="Integer"></id>
        <result property="acc" column="accound" javaType="String"></result>
        <result property="password" column="password" javaType="String"></result>
        <result property="name" column="name" javaType="String"></result>
        <result property="userClass" column="user_class" javaType="Integer"></result>
        <result property="houseId" column="house_id" javaType="String"></result>
        <result property="ruzhuTime" column="ruzhu_time" javaType="java.util.Date"></result>
        <result property="outTime" column="out_time" javaType="java.util.Date"></result>
        <result property="ban" column="ban" javaType="String"></result>
        <result property="isDelete" column="is_delete" javaType="String"></result>

    </resultMap>

    <select id="select" parameterType="String" resultMap="resultMap">
        select * from users where accound = #{acc}
    </select>


</mapper>

6.biz业务层内容

在biz包中新建一个接口类:GlobalBiz

并添加方法。

再impl包中添加其实现类:GlobalBizImpl

重写接口方法:

类前面添加@Service注解,提示Spring这个类是服务层的类;

导入的UserDao类的对象要添加@Autowired注解,自动注入;

7.web层内容

新建控制器类LoginController

类的前面添加Controller注解,提示Spring这是一个控制器类;

导入的业务层对象要进行自动注入;

toLogin()方法前添加@RequestMappiong注解,value值设置为to_login,指的是网站的url中的to_login路由。也就是说,url访问http://localhost:8080/to_login此路径的时候执行这个方法。方法的返回值login指的是访问项目静态资源文件login.jsp!

login()方法要进行登录操作,因此需要添加HttpSession类的对象,因为此方法要接收前端发送过来的账号密码数据,因此需要添加@RequestParam注解。acc和password形参跟前端的<input type="text" name="acc"/>的input标签的name属性的名字要一样;

login()方法接收数据后首先进行是否为空和长度大小等进行判断,如果有问题,则利用session添加参数的方法进行添加“键”和“值”(这里的键是warn,值是提示信息),并return 重定向(redirect:)回to_login路由,to_login路由返回到登录界面;

login()方法接收数据,进行判断无误后利用业务层方法进行登录操作,如果查询到存在此用户,则session添加参数,并把user对象添加到session,并重定向到self方法,让self方法访问登录后的self页面。

8.准备前端页面

在WEB-INF中的pages文件夹里添加login.jsp和self.jsp

login.jsp:

①:因为要用到jsp的标签 c,所以①添加

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

②:c标签,此标签是用来接收session的warn参数的信息的

③:提交到LoginController的@RequestMapping value为“login”的路由方法

注意,这里的css的引入路径,参照我的项目静态资源目录。还有就是input标签的name属性值。

self.jsp:

登录成功后,在页面中取出登录成功后用户的名称。

9.配置tomcat

点击IDEA右上角的下拉框的Edit.....,我这里配置过了的。

按顺序操作添加:

②:修改项目路径为to_login,直接访问Controller对应的方法路由。

③:也可以修改每次修改项目文件的时候服务器做什么

 

点击 + 号,然后选择有exploded后缀的选项,接着修改④为 /,然后点击“Apply”。

10.验证登录

开启tomcat服务器。

查看url地址:

 

直接点击登录按钮:

输入长度不足为5的账号密码:

输入错误的账号密码:

输入正确的账号密码:super,123456

注意url的路由名称,已经登录成功,页面显示用户的名称了。

最后

这篇文章写作的周期有几天,中途还因为SpringMVC拦截静态资源的问题,项目从头到尾弄多了一次,应该没有漏掉的地方,希望我在总结的时候能帮到您,下篇的文章讲如何防止用户未进行登录操作,在url直接输入某路由访问系统并系统操作数据,主要依赖拦截器技术。

4月更新

控制器层:

package com.myhomes.controller;

import com.myhomes.biz.GlobalBiz;
import com.myhomes.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

@Controller("loginController")
public class LoginController {

    @Autowired
    private GlobalBiz globalBiz;

    @RequestMapping(value = "/to_login")
    public String toLogin(){
        return "login";
    }

    @RequestMapping(value = "/login")
    @ResponseBody
    public Map<String,String> login(HttpSession session,@RequestBody Map<String,String> map){
        Map<String,String> map2 = new HashMap<>();

        String acc = map.get("acc");
        String password = map.get("password");

        User user = globalBiz.login(acc,password);
        if (user == null){
            map2.put("message","false");
            map2.put("error","用户名或密码输入错误!");
            return map2;
        }else{
            session.setAttribute("userId",user.getId());
            map2.put("message","success");
            map2.put("uid",String.valueOf(user.getId()));
            map2.put("uName",user.getName());
            return map2;
        }
    }

    @RequestMapping(value = "/self")
    public ModelAndView self(@RequestParam String uid,@RequestParam String uName){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("uid",uid);
        modelAndView.addObject("uName",uName);
        modelAndView.setViewName("self");
        return modelAndView;
    }
}

前端页面及提交代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<html>
<head>
    <title>××管理系统</title>
    <link rel="stylesheet" type="text/css" href="css/index.css"/>
    <link rel="stylesheet" href="layui/css/layui.css">
    <script src="layui/layui.js"></script>
</head>
<body>
<div id="main">
    <%--<c:if test="${not empty warn}">--%>
        <%--<h2 color="red" align="center"><c:out value="${warn}" /></h2>--%>
    <%--</c:if>--%>
        <form class="layui-form" name="login" method="post" style="position: fixed;background-color: #FFFFFF;left: 40%;top: 30%;width: 340px;height: 220px;border-radius: 16px;box-shadow: 0 0 3px #303030;opacity: 0.8;">
            <div class="layui-form-item" style="padding-top: 30px;">
                <label class="layui-form-label" style="font-size: 18px;">账号:</label>
                <div class="layui-input-block">
                    <input class="layui-input" style="width: 200px;" required  lay-verify="account" type="text" name="acc" placeholder="请输入账号" maxlength="11" onkeyup="this.value=this.value.replace(/[^\w\.\/]/ig,'')"/>
                </div>
            </div>
            <div class="layui-form-item" style="padding-top: 10px;">
                <label class="layui-form-label" style="font-size: 18px;">密码:</label>
                <div class="layui-input-block">
                    <input class="layui-input" style="width: 200px;" required  lay-verify="password"  type="password" name="password" placeholder="请输入密码" maxlength="20" onkeyup="this.value=this.value.replace(/[^\w\.\/]/ig,'')"/>
                </div>
            </div>
            <div class="layui-form-item" style="padding-top: 10px;">
                <input type="button" class="layui-btn layui-btn-normal" style="display:block;margin:0 auto;" value="登录" id="login_button">
            </div>
        </form>
</div>
</body>
<script src="js/jquery-1.8.3.min.js" type="text/javascript" ></script>
<script>
    $(document).ready(function () {
        layui.use('layer', function(){
            var layer = layui.layer;
            $("#login_button").click(function () {
                var acc = $("input[name=acc]").val();
                var pass = $("input[name=password]").val();
                if (acc.length < 5){
                    layer.alert('账号长度不足',{
                        title:"提示"
                    });
                    return false;
                }if (pass.length < 5){
                    layer.alert('密码长度不足',{
                        title:"提示"
                    });
                    return false;
                }
                $.ajax({
                   type:"post",
                   url:"/login",
                    contentType:"application/json;charset=UTF-8",
                    dataType:"json",
                    data:JSON.stringify({
                        acc:acc,
                        password:pass
                    }),
                    success:function (data) {
                        if (data.message === "false") {
                            layer.alert(data.error,{
                                title:"错误"
                            });
                        }
                        if (data.message === "success") {
                            var uid = data.uid;
                            var uName = data.uName;
                            window.location.href="/self?uid="+uid+"&uName="+uName;
                        }
                    }
                });
            });
        });
    });
</script>
</html>

启动成功后

直接点击【登录】按钮,提示:

密码长度不足,提示:

故意输入不存在的账号及密码:

右侧XHR栏是有数据的,状态200意味着成功将数据提交到服务器了,提交的数据能看到,服务器返回的数据也能看到。

进行成功登录操作:

成功了。

结尾

不出意外,这是最后的更新了。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值