ssm学习总结

目录

一、Mybatis

1、pom.xml

标签中添加依赖

标签中指定资源文件位置

2、jdbc.properties

3、SqlMapperConfig.xml

4、XXXMapper.xml

指定参数位置

字符串替换

#{}占位符和${}占位符

返回主键值

 入参是map

接口XXXMapper.class 和 XXXMapper.xml映射类型名

动态代理的实现规范:

动态代理访问的步骤

标签封装SQL语句或字段,标签引入来调用

 循环遍历

 条件的更新

分页功能

5、 test测试

二、Spring

 1、pom.xml

2、 applicationContext.xml

test测试

三、SpringMvc

1、 pom.xml

2、springmvc.xml

3、web.xml

4、数据提交

5、转发与重定向

四、ssm整合

1、pom.xml

2、applicationContext_mapper.xml

3、applicationContext_service.xml

4、springmvc.xml

5、web.xml

6、sm的单元集成测试




一、Mybatis

1、pom.xml

<dependencies>标签中添加依赖

<!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.8</version>
    </dependency>

    <!--mysql依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
    </dependency>

<build>标签中指定资源文件位置

    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>

      <resource>
        <directory>src/test/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
    </resources>

2、jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/s_t?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=000

3、SqlMapperConfig.xml

 内容详情:

  1. <properties>读取jdbc.properties属性
  2. <settings>标签设置日志
  3. 设置别名
    1. <typeAlias>设置单个实体类别名
    2. <typeAliases><package /></typeAliases>设置包下的全部实体类别名
  4. <environments>配置环境变量
    1. 配置事务管理器
                      type:指定事务管理的方式
                      JDBC:事务的控制交给程序员处理
                      MANAGED:有容器(spring)来管理事务
    2. 配置数据源
                      type:指定不同的配置方式
                      JNDI:Java命名目录接口,在服务器端进行数据库连接池的管理,表示使用上下文中的数据源
                      POOLED:使用数据库连接池
                      UNPOLLED:不使用数据库连接池
    3. -配置数据库连接的基本参数
                          private String driver;
                          private String url;
                          private String username;
                          private String password;
  5. <mappers>注册mapper.xml文件
    1. 单个注册 <mapper class="com.bjpowernode.mapper.CourseMapper"></mapper>
    2. 批量注册 <package name="com.bjpowernode.mapper"/>
    3. 属性名解析
      1. resource:从resources目录下找指定名称的文件注册
      2.  url:使用绝对路径注册
      3. class:动态代理方式下的注册
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

    <!--读取属性文件(jdbc.properties)
        属性:resources:从resources目录下找指定名称的文件加载
             url:使用绝对路径加载属性文件
    -->
<configuration>
    <!--读取jdbc.properties属性-->
    <properties resource="jdbc.properties"></properties>


    <!--
        设置日志输出底层执行的代码
        name和value中的值都是固定的
    -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>


    <!--注册实体类的别名-->
        <!--
            单个实体类别名的注册:
            可以在将替代为parameterType="student"
                         resultType="student"
            <typeAlias type="com.bjpowernode.pojo.Student" alias="student"></typeAlias>
        -->
    
    <typeAliases>
        <!--
            批量注册别名
            别名是类名的驼峰命名法(规范)
        -->
        <package name="com.bjpowernode.pojo"/>
    </typeAliases>


    <!--配置环境变量-->
    <!--
        配置数据库的环境变量
        当需要使用时,default选取id中的值,即可选择指定的数据库配置
    -->
    <environments default="development">
        <environment id="development">
            <!--配置事务管理器
                type:指定事务管理的方式
                JDBC:事务的控制交给程序员处理
                MANAGED:有容器(spring)来管理事务
            -->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源
                type:指定不同的配置方式
                JNDI:Java命名目录接口,在服务器端进行数据库连接池的管理,表示使用上下文中的数据源
                POOLED:使用数据库连接池
                UNPOLLED:不使用数据库连接池
            -->
            <dataSource type="POOLED">
                <!--配置数据库连接的基本参数
                    private String driver;
                    private String url;
                    private String username;
                    private String password;
                -->
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    
    <!--注册mapper.xml文件
        resource:从resources目录下找指定名称的文件注册
        url:使用绝对路径注册
        class:动态代理方式下的注册
    -->
    <mappers>
        <mapper class="com.bjpowernode.mapper.CourseMapper"></mapper>
        <!--批量注册
            <package name="com.bjpowernode.mapper"/>
        -->
    </mappers>
</configuration>

4、XXXMapper.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
    mapper:是整个文件的大标签,用来开始和结束xml文件
    属性:namespace:指定命名空间(相当于包名),用来区分不同mapper.xml文件中相同的id属性
-->
<mapper namespace="zar">
    <!--
        完成查询全部学生的功能
        List<Student> getAll();
            resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型
            parameterType:如果有参数,则通过他来指定的参数类型
            (如果传递的参数有两个或以上就不需要写 parameterType)
    -->
    <select id="getAll" resultType="com.bjpowernode.pojo.Student">
        select sno,sname,ssex,sage,sdept from student
    </select>

    <!--
        按主键sno查询学生信息
        Student getById(String sno);
    -->
    <select id="getBySno" parameterType="string" resultType="com.bjpowernode.pojo.Student">
        select sno,sname,ssex,sage,sdept
        from student
        where sno like '%${sno}%'
    </select>

    <!--
        增加学生
        int insert(Student stu);
        #{?}:中括号中内容为实体类中定义的属性名
            private String sno;
            private String sname;
            private String ssex;
            private Integer sage;
            private String sdept;
    -->
    <insert id="insert" parameterType="com.bjpowernode.pojo.Student">
        insert into student (sno,sname,ssex,sage,sdept) values (#{sno}, #{sname}, #{ssex}, #{sage}, #{sdept})
    </insert>

    <!--
        删除学生
        int delete(String sno);
    -->
    <delete id="delete" parameterType="int">
        delete from student where sno like '%${sno}%'
    </delete>

    <!--
        更新学生
        int update(Student stu);
    -->
    <update id="update" parameterType="com.bjpowernode.pojo.Student">
        update student set sno=#{sno}, sname=#{sname}, ssex=#{ssex}, sage=#{sage}, sdept=#{sdept}
        where sage=#{sage}
    </update>

<!--
        List<Course> getAllMap();
        使用resultMap手工完成映射
    -->
    <resultMap id="courseMap" type="course">
        <!--主键绑定
            property 中的值要和实体类中的主键属性名一直
            column 中的值要和数据库中的主键列名一直
        -->
        <id property="cno" column="cno"></id>
        <!--非主键绑定
            property
            column      中的值和主键绑定用法一样
        -->
        <result property="cname" column="cname"></result>
        <result property="cpno" column="cpno"></result>
        <result property="ccredit" column="ccredit"></result>

        <!--当一方有另一方的集合或一对多,则使用此完成映射   <collection property="" column=""></collection>
            当一方持有另一方的对象或多对一时,则使用此映射   <association property="" javaType=""></association>

            <collection property="" column="">
            主键绑定
                property 中的值要和实体类中的主键属性名一直
                column 中的值要和数据库中的主键列名一直

            <id property="cno" column="cno"></id>
             非主键绑定
                property
                column      中的值和主键绑定用法一样

            <result property="" column=""></result>

            </collection>
        -->
    </resultMap>
    <select id="getAllMap" resultMap="courseMap">
        select cname, cpno, ccredit
        from course
    </select>



    <!--
        多表映射查询
        <resultMap id="courseMap" type="course">
            <id property="cno" column="cno"></id>

            <result property="cname" column="cname"></result>


         ///这边放置的就是 表table2 绑定的
            <collection property="" column="">
                <id property="" column=" "></id>

                <result property="" column=""></result>
            </collection>
        </resultMap>

        <select id="getAllMap" resultMap="courseMap">
            select cname, cpno, ccredit
            from table1 t1 inner join table2 t2 on t1.a=t2.b
        </select>
        即分别给 table1表 取别名 t1 ,给 table2表 取别名 t2
        关联两表中等价的属性值查找,即 t1 中的 a列值 与 t2 中的 b列值 相等
        此外,inner 指两表等价
             left 指重点在于左表
             right 指重点在于右表
    -->
</mapper>

指定参数位置

18.指定参数位置
如果入参是多个,可以通过指定参数位置进行传参,是实体包含不住的条件.实体类只能封装住成员变量的条件.如果某个成员变量要有区
间范围内的判断,或者有两个值进行处理,则实体类包不住.
例如:查询指定日期范围内的用户信息.

<!--
//查询指定日期范围内的用户
List<Users> getByBirthday (Date begin, Date end) ;
-->
<select id="getByBirthday" resultType="users/>
select <include refid="allCo1umns"> </ inqlude>
from users 
where birthday between #{arg0} and #{arg1}
</ select>

字符串替换

需求:模糊地址或用户名查询
select * from users where username like 18小8' ;
select * from users where address like 18市8 '

<!--
//模糊用户名和地址查询
//如果参数超过一个,则parameterType不写
//接口语句
-->
List<Users> getByNameOrAddress (
        @Param ("columnName") ===>为 了在sq1语句中使用的名称
        String columnName , 
        @Param ("columnValue") ===> 为 了在sq1语句中使用的名称
        String columnValue) ; 
//xml语句
<select id="getByNameOrAddress" resultType="users">
    select id,username , bi rthday , sex , address
    from users
    where $ {columnName} like concat('8' ,#{columnValue},'8') == =>此处使用的是0Param注解里的名称
</ select>

#{}占位符和${}占位符

#{}占位符
传参大部分使用#{}传参,它的底层使用的是Preparedstatement对象,是安全的数据库访问,防止sql注入.
#{}里如何写,看parameterType参数的类型

1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写.
<select id="getById" parameterType="int" resultType="users"> == == =>入参类型是简单类型
    select id, username , bi rthday , sex, address 
    from users
    where id=#{zar} ===>随便写
</select>

2) parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写.
<insert id=" insert" parameterType= ="users" > === => 入参是实体类
    insert into users (username, birthday, sex, address) values (# {userName} , 
    #{birthday},#{sex} ,#{address}) == =>成员变量名称
</insert>


${}字符串拼接或字符串替换
1)字符串拼接,一般用于模糊查询中.建议少用,因为有sql注入的风险.
也分两种情况,同样的看parameterType的类型

A.如果parameterType 的类型是简单类型,则${}里随便写,但是分版本,如果是3.5.1及以下的版本,只以写value.
<select id="getByName" parameterType=" string" resultType="users"> === =>入参是简单类型
    select id, username , birthday , sex , address
    from users
    where username like ' 8${zar}8'== =>随便写
</select>

B.如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称.(现在已经少用)
C.优化后的模糊查询(以后都要使用这种方式)
<select id="getByNameGood" parameterType=" string" resultType="users">
    select id, username , birthday , sex , address
    from users 
    where username like concat('8' ,#{name}, 181)
</ select>

返回主键值

在插入语句结束后,返回自增的主键值到入参的users对象的id属性中.
<insert id=" insert" parameterType="users" > >
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        select last_ insert_ id()
    </ selectKey>
    insert into users (username, birthday, sex, address) values (# {userName} , #{birthday}             
    ,#{sex} , #{address})
</ insert>

<selectKey>标签的参数详解:
    keyProperty:users对象的哪个属性来接返回的主键值
    resultType:返回的主键的类型
    order:在插入语句执行前,还是执行后返回主键的值


UUID这是一个全球唯---字符串,由36个字母数字中划线组.
UUID uuid = UUID. randomUUID() ;
System. out . println (uuid. toString() . replace("-", "") . substring(20)) ;

 入参是map

入参是map(重点掌握)
如果入参超过一一个以.上,使用map封装查询条件,更有语义,查询条件更明确.
    <!--
        //入参是map
        List<Users> getByMap (Map map) ;
        # {birthdayBegin} :就是map中的key
    --->
<select id="getByMap" resultType="users" >
    select <include refid="allColumns"> </ include>
    from users
    where birthday between # {birthdayBegin} and # [birthdayEnd|
</ select>

测试类中
@Test
public void testGetByMap() throws ParseException {
Date begin = sf.parse("1999-01-01") ;
Date end = sf.parse("1999-12-31") ;
Map map = new HashMap<>() ;
map. put ("birthdayBegin" ,begin) ;
map. put ("pirthdayEnd, end) ;
List<Users> list = uMapper . getByMap (map) ;
list. forEach (users -> System. out . println (users)) ;
}

接口XXXMapper.class 和 XXXMapper.xml映射类型名

动态代理的实现规范:

  1. UsersMapper. xml文件与UsersMapper. java的接口必须同-一个目录下。
  2. UsersMapper. xml文件与UsersMapper. java的接口的文件名必须一致,后缀不管.
  3. Use rMapper . xml文件中标签的id值与与UserMapper. java的接口中方法的名称完全一- 致.
  4. UserMapper . xml文件中标签的parameterType属性值与与UserMapper . java的接口中方法的参数类型完全一致.
  5. UserMapper . xml文件中标签的resultType值与与UserMapper . java的接口中方法的返回值类型完全一致.
  6. UserMapper . xml文件中namespace属性必须是接口的完全限定名称com. bj powernode . mapper . UsersMapper
  7. 在SqlMapConfig . xml文件中注册mapper文件时,使用class=接口的完全限定名称com. bjpowernode . mapper .UsersMapper.

动态代理访问的步骤

  1. 建表Users
  2. 新建maven工程,刷新可视化
  3. 修改目录
  4. 修改pom.xml文件,添加依赖
  5. 添加jdbc . propertis文件到resources目录下
  6. 添加sqlMapConfig . xml文件
  7. 添加实体类
  8. 添加mapper文件夹,新建UsersMapper接口
  9. 在mapper文件夹“下,新建UsersMapper. xml文件,完成增删改查功能
  10. 添加测试类,测试功能

<sql>标签封装SQL语句或字段,<include>标签引入来调用

<sql id="allColumns">
    cno,cname,cpno,ccredit
</sql>

<select id="getByCpnos" resultType="course">
        select 
            <include refid="allColumns"></include>
        from course
        where cpno in
        (
            <foreach collection="array" item="cpno" separator=",">
                #{cpno}
            </foreach>
        )
</select>

 <foreach>循环遍历

 参数详解:

  • collection:用来指定入参的类型,如果是List集合,则为1ist,如果是Map集合,则为map,如果是数组,则为array.
  • item:每次循环遍历出来的值或对象
  • separator:多个值或对象或语句之间的分隔符
  • open:整个循环外面的前括号
  • close:整个循环外面的后括号
用来进行循环遍历,完成循环条件查询,批量删除,批量增加,批量更新.

查询实现
<select id="getByIds" resultType="users">
    select <include refid="allColumns"></include>
    from users
    where id in
    <foreach collection="array" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</select>

批量删除实现

<delete id="deleteBatch" >
    delete from users
    where id in
        <foreach collection="array" item="id" separator="," open="(" close=") ">
            #{id}
        </foreach>
</delete>

批量增加实现

<insert id=" insertBatch">
    insert into users (username,birthday, sex, address) values
        <foreach collection="list" item="u" separator="," >
            (#{u. userName} , #{u .birthday} , #{u. sex} , #{u. address})
        </foreach>
</insert>

 <set>条件的更新

但是注意至少更新-列,这种方式如果实体类中的成员变量没有给值,则数据库中相应的字段不更改

<update id= "updateContidion" parameterType= "users">
    update users
    <set>
        <if test="userName != null">
            username= #{userName},
        </if>
    </set>
    where id= #{id}
</update>

分页功能

  • 添加依赖
<!--分页依赖-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.4</version>
</dependency>
  • SqlMapperConfig.xml中添加插件
<!--配置分页插件-->
<plugins>
    <plugin interceptor="com.github.pagehelper.pageInterceptor"></plugin>
</plugins>
  • 使用
@Test
public void pageTest() throws IOException {
   InputStream resource = Resources.getResourceAsStream("mybatisConfig.xml");
   SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
   SqlSession sqlSession = factory.openSession();
   studentMapper = sqlSession.getMapper(StudentMapper.class);

   //数据操作前设置分页        
   PageHelper.startPage(1, 3);
   List<Student> list = studentMapper.getAll();
   list.forEach(student -> System.out.println(student));
   sqlSession.close();
}         

 

5、 test测试

//***在所有的增删改查后必须手工提交事务!!!  
这是直接使用xml文件中的方式  
    @Test
    public void testA() throws IOException {
        //使用文件流读取核心配置文件SqlMapperConfig.xml
        InputStream in1 = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in1);
        //取出sqlSession的对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作
        List<Student> list = sqlSession.selectList("zar.getAll");
        list.forEach(student -> System.out.println(student));
        //关闭sqlSession
        sqlSession.close();
    }


这是通过XXXMapper.class接口方式
    @Test
    public void testGetAll() throws IOException {
        //读取核心配置文件
        InputStream in1 = Resources.getResourceAsStream("SqlMapperConfig.xml");
        //创建工厂对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in1);
        //取出sqlSession
        SqlSession sqlSession = factory.openSession();
        /*
        *   执行动作
        * 取出动态代理的对象,完成接口方法中的调用,实则是调用xml文件中相的标签的功能
        */
        CourseMapper courseMapper = sqlSession.getMapper(CourseMapper.class);
        //查看接口类型
        System.out.println(courseMapper.getClass());  
        //调用接口方法,mybatis已经为功能代理出来了  
        List<Course> list = courseMapper.getAll();      
        list.forEach(course -> System.out.println(course));
        //关闭
        sqlSession.close();
    }



二、Spring

 1、pom.xml

<!--spring核心IOC-->
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.19</version>
</dependency>

<!--aspects依赖-->
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.19</version>
</dependency>

<!--做spring事务时用到-->
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.3.19</version>
</dependency>

2、 applicationContext.xml

 内容详情:

  1. 添加包扫描
  2. 绑定aspectj
  3. 事务处理
    1. 添加事务处理器
      1. 配置数据源
    2. 添加事务注解的驱动
<!--添加包扫描,这是将该包下的都创建对象-->
<context:component-scan base-package="com.hdy.s01"></context:component-scan>


<!--创建单个对象-->
<bean id="school" class="com.hdy.pojo2.School"></bean>


<!--绑定aspectj-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


<!--事务处理-->
<!--1、添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--因为事务必须关联数据库处理,所以要配置数据源-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--2、添加事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

创建对象赋值

 赋值方式

  1. setter注入
    1. 简单类型注入值使用value属性
    2. 引用类型注入值使用ref属性
    3. 必须要注意:使用setter注入必须提供无参的构造方法,必须提供setXXX()方法.
  2. 构造方法注入
    1. 构造方法的参数名称注入
    2. 构造方法的参数下标注入
    3. 构造方法的参数默认顺序注入
基于xml的IOC
1)创建对象
<!--创建学生对象
        等同于 Student stu = new Student();
        id:创建对象的名称
        class:创建对象的类型,底层通过反射构建对象
-->
<bean id="stu" class="com. bj powernode . pojo. Student"></bean>


2)给创建的对象赋值
A.使用setter注入
注入分为简单类型注入和引用类型注入
简单类型注入值使用value属性
引用类型注入值使用ref属性
必须要注意:使用setter注入必须提供无参的构造方法,必须提供setXXX()方法.
<!--创建学生对象-->
<bean id="stu" class=" com. bj powe rnode . pojo2. Student">
<property name="name" value=" 李四"></property> = ==>简 单类型注入
<property name="age" value="22"></ property>
<property name=" school" ref=" school"></property> == == => 引用类型注入
</bean>
<!--创建学校对象-->
<bean id=" school" class=" com. bj powernode . pojo2. School">
<property name="name" value= ="清华大学"></property>
<property name="address" value= ="海淀区"></property>
</bean>


B.使用构造方法注入值
<!--创建学校的对象,使用构造方法参数名称注入值-->
<bean id="school" c1 ass="com. bipowe rnode . pojo3. School">
    <constructor-arg name="namel" value="清华 大学"></constructor- arg>
    <constructor-arg name="address1" value="海淀区">< / const ructor-arg>
</bean>

<!--创建学生对象,使用构造方法的参数的下标注入值-->
<bean id="stu" class="comxpowernode. pojo3. Student">
    <constructor-arg index="0" value="钱七"></constructor-arg> 
    <constructor-arg index="1" value="22"></const ructor-arg>
    <constructor-arg index="2" ref="school"></constructor-arg>
</bean>

<!--创建学生对象,使用默认的构造方法的参数顺序-->
<bean id=" stuSequence" class="com. bjpowe rnode .pojo3 .Student">
    <constructor-arg value="陈+"></constructor-arg>
    <constructor-arg value="22"></constructor-arg>
    <constructor-arg ref="school"></constructor-arg>
</bean>

基于注解的IOC

注解annotation

  1. 创建对象的注解
    1. @Component:可以创建任意对象. 
    2. @Controller:专门用来创建控制器的对象(Servlet),这种对象可以接收用户的请求,可以返回处理结果给客户端.
    3. @Service:专门用来创建业务逻辑层的对象,负责向下访问数据访问层,处理完毕后的结果返回给界面层.
    4. @Repository:专门用来创建数据访问层的对象,负责数据库中的增删改查所有操作。
  2. 依赖注入的注解

    1. 值类型的注入
      1. @Value:用来给简单类型注入值
    2. 引用类型的注入
      1. @Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入.
      2.  @Autowired @Qualifier:使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入.

AspectJ(掌握)

  1.  AspectJ中常用的通知有四种类型:
    1. 前置通知@Before
    2. 后置通知@AfterReturning
    3. 环绕通知@Around
    4. 最终通知@After
    5. 定义切入点@Pointcut
  2. 切入点规范的公式:
    1. execution (访问权限  方法返回值  方法声明(参数)  异常类型)

    2. 简化后的公式:execution(方法返回值  方法声明(参数) )

  3. 用到的符号:

    • *代码任意个任意的字符(通配符)

    • ..如果出现在方法的参数中,则代表任意参数

        如果出现在路径中,则代表本路径及其所有的子路径

示例:
execution(public * *(..)) :任意的公共方法
execution(* set*(..)) :任何一个以"set"开始的方法
execution(* com.xyz.service.impl.*.*(..)):任意的返回值类型,在com.xyz.service.impl包下的任意类的任意方法的任意参数
execution(* com.xyz.service..*. *(..)):任意的返回值类型, 在com. xyz . service及其子包下的任意类的任意方法的任意参数
com.xyz.service.a.b.*.*(..)
com.xyZ.service.*.*(. .)
execution(* *. .service.*.*(. .)) :service之前可以有任意的子包.
execution(* *.service.*.*(. .)) :service之前只有一 个包

test测试

    @Test
    public void testStudentSpring(){
        /*
        *由spring容器进行对象的创建
        * 要从spring容器中取出对象:首先是要创建容器对象,并且启动才可以取对象
        */
        ApplicationContext ac = new ClassPathXmlApplicationContext("s01/applicationContext.xml");

        Student student = (Student) ac.getBean("stu");
        System.out.println(student);
    }

三、SpringMvc

1、 pom.xml

<dependencies>添加依赖
<!--SpringMVC依赖-->
<dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-webmvc</artifactId>
       <version>5.2.21.RELEASE</version>
</dependency>
<!--servlet依赖-->
<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
</dependency>

2、springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 
       https://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/mvc 
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!--添加包扫描-->
    <context:component-scan base-package="com.hdy.controller"></context:component-scan>
    <!--
        不用添加视图解析器,因为处理的是Ajax请求
        但是必须要添加注解驱动,专门来处理Ajax请求
    -->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

3、web.xml

  1.  中文编码过滤器
  2. 注册SpringMvc框架
<?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_4_0.xsd"
         version="4.0">


    <!--中文编码过滤器配置-->
    <filter>
        <filter-name>encode</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--
        配置参数:
        private String encoding;
        private boolean forceRequestEncoding;
        private boolean forceResponseEncoding;
    -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRestEncoding</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>
            <!--
  	            加载配置文件
  	            默认加载规范:
  	            * 文件命名:servlet-name-servlet.xml====springmvc-servlet.xml
  	            * 路径规范:必须在WEB-INF目录下面
  	            修改加载路径:
            -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!--
            指定拦截什么样的请求:
            http:localhost:8080/index
            http:localhost:8080/index.jsp
            http:localhost:8080/index.action
            <a hrref="${pageContext.request.contextPath}/demo.action">访问服务器</a>
        -->
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
</web-app>

4、数据提交

post请求会产生中文乱码,而get请求就不会产生这个问题并且name="?", 值需要要变量名一样才能找到 

  1.  单个数据提交
    1. 参数名称和属性名称一致
  2. 对象封装提交
    1. 实体类参数名称和属性名称一致
  3. 动态占位符提交
    1. 仅限于超链接或地址栏提交数据,是一斜杠一个值,一缸一大括号
    2. 使用注解 @PathVariable 来解析
    3. 如果 {name} 中与 String myname 中变量名不同,可以用 @PathVariable(“name”) String myname来使用
  4. 映射名称不一样时提交
    1. 如果 {name} 中与 String myname 中变量名不同,可以用 @RequestParam("name") String myname来使用
  5. @RequestParam("name")和@PathVariable(“name”)区别:
    1. @RequestParam("name")是从请求参数中
    2. @PathVariable("name")是从请求路径中
  6. 手工数据提交
    1. 通过(HttpServletRequest  httpServletRequest)方式在java文件中赋值                                String name = httpServletRequest.getParameter("name");
              int age = Integer.parseInt(httpServletRequest.getParameter("age"));
    2. 如果类型不同需要转换成相应的类型 

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <h2>测试不同请求提交方式</h2>
<form action="${pageContext.request.contextPath}/req.action" method="post">
    <input type="submit" value="提交">
</form>
  <br>
<h2>单个数据提交</h2>
  <form action="${pageContext.request.contextPath}/one.action" method="get">
      姓名:<input name="myname"><br>
      年龄:<input name="age"><br>
      <input type="submit" value="提交">
  </form>
  <br>
<h2>对象封装数据提交</h2>
  <form action="${pageContext.request.contextPath}/two.action" method="post">
      姓名:<input name="name"><br>
      年龄:<input name="age"><br>
      <input type="submit" value="提交">
  </form>
<h3>
    post请求会产生中文乱码,而get请求就不会产生这个问题
    并且name="?", 值需要要变量名一样才能找到
</h3><br>
<h2>动态占位符提交</h2>
  <a href="${pageContext.request.contextPath}/three/展示/22.action">动态提交</a>
  <br>
<h2>映射名称不一样</h2>
  <form action="${pageContext.request.contextPath}/four.action" method="post">
      姓名:<input name="name"><br>
      年龄:<input name="age"><br>
      <input type="submit" value="提交">
  </form>
  <br>
<h2>手工提取数据</h2>
  <form action="${pageContext.request.contextPath}/five.action" method="post">
      姓名:<input name="name"><br>
      年龄:<input name="age"><br>
      <input type="submit" value="提交">
  </form>
</body>
</html>

DataSubmitAction

import com.hdy.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;

@Controller
public class DataSubmitAction {
    /*
         姓名:<input name="myname"><br>
         年龄:<input name="age"><br>
    */
    @RequestMapping("/one")
    public String one(String myname, int age){
        System.out.println("myname" + myname + ", age" + age);
        return "one";
    }

    @RequestMapping("/two")
    public String two(Users users){
        System.out.println(users);
        return "two";
    }


    /*
    * <a href="${pageContext.request.contextPath}"/three/展示/22.action>动态提交</a>
    * 仅限于超链接或地址栏提交数据,是一斜杠一个值,一缸一大括号
    * 使用注解 @PathVariable 来解析
    *
    * 如果 {name} 中与 String myname 中变量名不同,可以用 @PathVariable(“name”) String myname来使用
    * */
    @RequestMapping("/three/{name}/{age}")
    public String three(
            @PathVariable String name,
            @PathVariable int age){
        System.out.println("myname" + name + ", age" + age);
        return "three";
    }

    @RequestMapping("/four")
    public String four(
            @RequestParam("name") String myname,
            @RequestParam("age") int uage
            ){
        System.out.println("myname" + myname + ", age" + uage);
        return "four";
    }


    //@RequestParam("name")和@PathVariable(“name”)区别:
    //          @RequestParam("name")是从请求参数中
    //          @PathVariable("name")是从请求路径在




    @RequestMapping("/five")
    public String five(HttpServletRequest httpServletRequest){
        String name = httpServletRequest.getParameter("name");
        int age = Integer.parseInt(httpServletRequest.getParameter("age"));
        System.out.println("myname" + name + ", age" + age);
        return "five";
    }
}
当要解析ajax请求,必须要在springmvc.xml文件中添加注解驱动,还需要添加@ResponseBody
public class StudentListAction {
    @RequestMapping("/list")
    @ResponseBody   //解析ajax请求,必须要在springmvc.xml文件中添加注解驱动
    public List<Student> list(){
        List<Student> list = new ArrayList<>();
        Student stu1 = new Student("Tom", 12);
        Student stu2 = new Student("Jack", 12);
        Student stu3 = new Student("Hony", 12);
        list.add(stu1);
        list.add(stu2);
        list.add(stu3);

        return list;    //springmvc框架负责将集合转为json数组
    }
}

5、转发与重定向

  •  请求转发
    • 默认是请求转发,使用视图解析器拼接前缀后缀进行页面跳转
    • forward: 这组字符串可以屏蔽前缀和后缀的拼接
      • 如果不使用 forward 将会是 /admin/   /other.action.jsp 路径就会有问题
        return "forward:/other.action";
  • 重定向
    • redirect: 这组字符串可以屏蔽前缀后缀的拼接,实现重定向
       
@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 将会是 /admin/   /other.action.jsp 路径就会有问题
        return "forward:/other.action";
    }

    @RequestMapping("/three")
    public String three(){
        System.out.println("这是重定向跳转。。。。。");
        //redirect: 这组字符串可以屏蔽前缀后缀的拼接,实现重定向
        return "redirect:/admin/main.jsp";   //默认是请求转发,使用视图解析器拼接前缀后缀进行页面跳转
    }

    @RequestMapping("/four")
    public String four(){
        System.out.println("这是重定向action跳转。。。。。");
        //redirect: 这组字符串可以屏蔽前缀后缀的拼接,实现重定向
        return "redirect:/admin/other.action";   //默认是请求转发,使用视图解析器拼接前缀后缀进行页面跳转
    }

    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");   //可以当做刷子,规定输出样式
    /*
    注册单个日期处理注解
        @RequestMapping("/mydate")
        public String mydate(@DateTimeFormat(pattern = "yyyy-MM-dd")Data mydate){
            System.out.println(mydate);
            System.out.println(sf.format(mydate));
            return "main";
        }
    */

    //注册一个全局的日期处理注解
    @InitBinder
    public void initBinder(WebDataBinder dataBinder){
        dataBinder.registerCustomEditor(Data.class, new CustomDateEditor(sf, true));
    }
    @RequestMapping("/mydate")
    public String mydate(Data mydate){
        System.out.println(mydate);
        System.out.println(sf.format(mydate));
        return "main";
    }
}
@Controller
public class OtherAction {
    @RequestMapping("/other")
    public String other(){
        System.out.println("other的action访问");
        return "main";
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/one.action">1.请求页面跳转(默认)</a><br><br>
<a href="${pageContext.request.contextPath}/two.action">2.请求转发action跳转</a><br><br>
<a href="${pageContext.request.contextPath}/three.action">3.重定向页面</a><br><br>
<a href="${pageContext.request.contextPath}/four.action">4.重定向action</a><br>
<br><br>
<form action="${pageContext.request.contextPath}/mydate.action">
    日期:<input type="date" name="mydaye">
    <input type="submit" value="提交">
</form>
</body>
</html>

四、ssm整合

1、pom.xml

<dependencies>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
        <!--jsp-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2.1-b03</version>
        </dependency>
        <!--springmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.21.RELEASE</version>
        </dependency>
        <!--spring事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.20</version>
        </dependency>
        <!--spring jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.19</version>
        </dependency>
        <!--spring测试-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.22.RELEASE</version>
        </dependency>
        <!--Jackon-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.13.3</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.8</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.9</version>
        </dependency>
    </dependencies>

2、applicationContext_mapper.xml

  1.  读取属性文件
  2. 声明数据源,连接数据库
  3. SqlSessionFactoryBean创建SqlSessionFactory
  4. 注册mapper.xml
  5. 声明mybatis的扫描器
<?xml version="1.0" encoding="UTF-8"?>
<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 https://www.springframework.org/schema/context/spring-context.xsd">

    <!--读取属性文件-->
    <context:property-placeholder location="classpath:conf/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创建SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:conf/SqlMapConfig.xml"></property>
        <property name="typeAliasesPackage" value="com.hdy.dao.pojo"></property>
    </bean>

    <!--注册mapper.xml文件-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hdy.dao.mapper"></property>
    </bean>

    <!--声明mybatis的扫描器,创建dao对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <property name="basePackage" value="com.hdy.dao.mapper"></property>
    </bean>
</beans>

3、applicationContext_service.xml

  1.  导入applicationContext_mapper.xml整合sm
  2. 添加service层包扫描,这是将该包下的都创建对象
  3. 事务处理
    1. 添加事务管理器
      1. 因为事务必须关联数据库处理,所以要配置数据源
    2. 添加事务的注解驱动
<?xml version="1.0" encoding="UTF-8"?>
<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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <import resource="applicationContext_mapper.xml"></import>
    <!--声明service的注解所在的包名位置-->
    <context:component-scan base-package="com.hdy.service.impl"></context:component-scan>


    <!--事务配置-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

4、springmvc.xml

 内容详情:

  1. springmvc配置文件,声明controller和其他相关web对象
  2. 添加注解驱动,专门来处理Ajax请求(不用添加视图解析器,因为处理的是Ajax请求)<mvc:annotation-driven></mvc:annotation-driven>必须是(xmlns:mvc="http://www.springframework.org/schema/mvc")
<?xml version="1.0" encoding="UTF-8"?>
<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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--springmvc配置文件,声明controller和其他相关web对象-->
    <context:component-scan base-package="com.hdy.controller"></context:component-scan>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="suffix" value="/WEB-INF/jsp/"></property>
        <property name="prefix" value=".jsp"></property>
    </bean>

    <!--
    1、响应Ajax请求,返回json
    2、解决静态资源访问问题
    -->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

5、web.xml

  1.  中文编码过滤器配置
  2. 注册SpringMvc框架
  3. 注册Spring框架,即监听Spring
<?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_4_0.xsd"
         version="4.0">

    <!--注册中央调度器-->
    <servlet>
        <servlet-name>myweb</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:conf/springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>myweb</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--注册监听器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:conf/applicationContext_service.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--注册字符集过滤器-->
    <filter>
        <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

6、sm的单元集成测试

这边@RunWith(SpringJUnit4ClassRunner.class) 在pom.xml中添加的测试依赖需要版本4.12以上

这里 @ContextConfiguration(locations = {"classpath*:/conf/applicationContext_mapper.xml", "classpath*:/conf/applicationContext_service.xml"})  只使用classpath*, 如果使用classpath则会报读取报文件错误

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:/conf/applicationContext_mapper.xml", "classpath*:/conf/applicationContext_service.xml"})
public class MyTest {
    @Autowired
    private UsersService usersService;

    @Test
    public void testSelect(){
        List<MyUser> list = usersService.selectAllUser();
        list.forEach(myUser -> System.out.println(myUser));
    }
    @Test
    public void testInsert(){
        int num = usersService.addUser(new MyUser(6, "kitty", "man"));
        List<MyUser> list = usersService.selectAllUser();
        list.forEach(myUser -> System.out.println(myUser));
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值