SSM框架

框架介绍(Spring,SpringMVC,MyBatis)

框架:已经封装好的类以及规则内容(如何和数据库链接交互,页面之间的值的传递),可以使用已经封装好的类,只会考虑业务逻辑问题以简化开发

SSM:Spring, SpringMVC,Mybatis整合使用

MVC:浏览器向用户展示页面(html(JSP):view),Servlet与view进行数据驱动(Control决定展示什么样的view),并接受用户的输入(control),Model和Control进行数据交互(model层里面有业务逻辑和数据操作的内容),Model和database进行数据操作

Spring: 项目中的装配bean对象的工厂不需要程序员显示的创建对象,核心使用IOC技术(控制反转,依赖注入:抵消耦合度)

SpringMVC:利用拦截器拦截用户的请求并进行分析,然后寻找对应的controller

Mybatis:永久层框架(数据访问层)JDBC的一个封装操作(程序员只需要注意SQL语句)

MyBatis

什么是MyBatis框架

MyBatis支持普通的SQL查询,存储过程,几乎消除了JDBC代码和参数的设置(需要下载框架的JAR:Mybatis-connector-java.jar,mybatis.jar),不需要自己在创建Connection,statement的创建,也不需要对查询结果一条一条查询,并组装对象

MyBatis使用XML或者注解来配置以及原始映射将JAVA对象映射成数据库当中的记录

Mybatis 的项目创建以及XML映射配置信息

Mybatis的XML配置文件当中包含了一系列影响Mybatis的属性信息

<?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">   <!-- dtd文件:约束文件:约束节点与节点之间的顺序-->
<configuration>											 <!-- 根节点-->
    <environments default="development">                 <!-- 表明开发环境相关信息-->
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>   <!--链接的数据库的相关信息——$表示需要给出变量的信息-->
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--这里是在注册mapper文件,需要给出mapper的全类名-->
        <mapper resource="com/test/UserMapper.xml"></mapper>
    </mappers>
</configuration>

可以利用properties进行设置变量的值,properties节点将会被放在configuration节点中,用于提供数据库参数数据

<properties resource="org/mybatis/example/config.properties"> <!--外部链接的文件,需要放置在configuration节点中-->
</properties>
driver=com.mysql.jdbc.Driver 
url=jdbc:mysql://localhost:3306/webproject?characterEncoding=utf-8&serverTimezone=GMT    <!--一定要加上时区-->
username=root
password=123456

MyBatis 表映射和对应的mapper文件

mapper映射:用于告诉mybatis将数据表中的记录封装成什么样的对象

需要创建映射类,映射于数据表

mapper 文件

本质上仍旧是XML文件放置SQL语句,以及告诉mybatis什么是映射类(每一张数据表往往都会有自己的映射文件)[以表名+Mapper明明的XML文件]

  1. 在mapping的XML文件当中同样需要加上dtd约束条件(但是约束的是mapper)
  2. mapping的根节点不是configuration而是mapper
  3. 在mapper根节点当中有select,update,insert等标签(分别都有增删改查)
<?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">
<!-- parameterType指的是传入参数的类型,resultType指的是返回结果的类型,id只是对SQL语句进行命名-->
<mapper namespace="com.test.UserMapper">
    <select id="selectEmail" resultType="com.test.User">
        select * from webUser
    </select>
</mapper>
SqlSession 对象

SqlSessionFactory对象:用于创建SqlSession对象

SqlSessionFactoryBuilder:用于创建SqlSessionFactory对象

均在配置XML文件当中进行创建,放在DAO(数据处理层)

用于调用在mapper文件当中已经写好了的SQL语句,底层已经封装了JDBC的操作

看似创建的对象很多,其实在利用Spring框架进行整合之后不会那么的复杂

package com.dao;

import com.test.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.util.List;

public class UserDao {
    //这个方法用于查询所有的用户信息
    public List<User> selectUser(){
        //1. 创建SqlSessionFactoryBuilder
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("mybatis.xml");   
        //读取xml配置信息(包括数据库的信息)
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //2. 创建SqlSessionFactory
        SqlSessionFactory factory = builder.build(inputStream);               
        //创建了一个针对一个数据库的factory
        //3. 创建SqlSession
        SqlSession sqlSession = factory.openSession();
        List<User> list = sqlSession.selectList("com.test.UserMapper.selectEmail");   
        //sqlsession当中封装了大量的sql的操作,比如selectList就是直接返回结果集,里面的参数指的是sql语句可能需要的参数
        sqlSession.close();
        return list;       
    }
}

mapper中使用条件查询(如何传入参数)

单一条件查询
<select id="selectUserByEmail" resultType="com.test.User" parameterType="String">
    select * FROM user where email=#{email}
</select>
public User selectUserByEmail(String email){
    SqlSession sqlSession = UserDao.getFactory().openSession();
    User user = sqlSession.selectOne("com.test.UserMapper.selectUserByEmail", email);  
    //第一个参数是SQL储存的节点位置,后面的参数是传入SQL的参数
    return user;
}
  1. 在select标签当中需要给出parameterType也就是传入参数的类型(JAVA中的类型,不是SQL中的类型)
  2. 在SQL语句当中使用的占位符不再是JDBC中的?而是#{参数名称}(也可以使用$ 代替#:#会在SQL语句中自动加上引号,但$不会需要在大括号中加上引号,但是假设传入字段的名称或者表的名称就用$ 因为原来的SQL语句也不需要加上引号)
  3. 在DAO层里面使用SqlSession的方法时就需要传入参数
多个条件查询
<select id="selectUserByEmailAndPassword" resultType="com.test.User" parameterType="com.test.User">
    select * FROM user where email=#{email} and password=#{password}
</select>

传入的参数就可以创建一个参数类,包含了需要的参数(SQL中的占位符只需要写出类中的成员属性就可以了)

public User selectUserByEmailAndPassword(){
    SqlSession sqlSession = UserDao.getFactory().openSession();
    User user = new User("123456@qq.com","123","eric");
    User user1 = sqlSession.selectOne("com.test.UserMapper.selectUserByEmail", user);
    return user1;
}

TypeAliases配置

用于简化XML用引用类而写的全类名

<typeAliases>
    <typeAlias type="com.test.User" alias="User"/>
</typeAliases>
  1. alias表示别名,type指的是全类名
  2. 之后使用类,不需要全类名
<typeAliases>
    <package name="com.test"/>
</typeAliases>

使用package标签,就可以在mapper文件当中省略掉所有该包名

在配置文件当中注册mapper时不能省略报名,那个是路径使用/

Log4j打印底层SQL代码

  1. 同样是先行导入jar包
  2. 在配置文件当中进行配置:在setting节点当中(在configuration根节点之中,properties节点之下)
<settings>
    <setting name="logImpl" value=" STDOUT_LOGGING"/>          <!--设置日志输出方式:会在控制台中输出-->
</settings>

mapper中使用添加数据

使用insert标签,大致使用方式和select标签差不了太多

<insert id="insertIntoUser" parameterType="User">
    insert into user values(#{email},#{password},#{Username})
</insert>
public void addUser(User user){
    SqlSession sqlSession = UserDao.getFactory().openSession();
    sqlSession.insert("insertIntoUser", user);
    sqlSession.commit();                                  //对于insert和update类型的修改需要commit也就是提交
    sqlSession.close();
}

mapper中使用数据修改和删除

<update id="updateUserByEmail" parameterType="User">
    update user set email=#{email},username=#{username},password=#{password} where email=#{email}
</update>

<delete id="deleteByEmail" parameterType="String">
    delete from user where email=#{email}
</delete>
public void updateByEmail(User user){
    SqlSession sqlSession = UserDao.getFactory().openSession();
    sqlSession.update("updateUserByEmail", user);
    sqlSession.commit();
    sqlSession.close();
}

public void deleteByEmail(String email){
    SqlSession sqlSession = UserDao.getFactory().openSession();
    sqlSession.delete("deleteByEmail", email);
    sqlSession.commit();
}

MyBatis的动态SQL

利用标签实现动态查询:if,choose,trim,foreach

if和where标签
<select id="selectUserByParameter" parameterType="User">
    select * from user 
    <where>
    <if test="email!=null">
        email=#{email}
    </if>
    <if test="password!=null">
        and password=#{password}
    </if>
    </where>
</select>
  1. where标签会自动根据情况去掉AND来符合SQL的语法
  2. 在使用where标签的过程当中,第一个条件的and需要去掉,接下来的条件都加上and或者or
  3. 对于text的字段,使用null,对于int可以在传入的时候自己去设置
choose和when和otherwise标签

和Java中的switch,case,default作用几乎相同,只能选择一个条件

<select id="selectUserByParameter1" parameterType="User" resultType="User">
    select * from user
    <where>
        <choose>
        <when test="email!=null">
            email=#{email}
        </when>
        <when test="password!=null">
            password=#{password}
        </when>
        <otherwise>
            
        </otherwise>
        </choose>
    </where>
</select>

假设有多个条件同时成立,只会进入第一个条件

set标签

用于更新数据,解决update只能更新固定字段的问题,使用在update标签之中

<update id="updateUserUsingSet" parameterType="User">
    update user
    <set>
        <if test="password!=null">password=#{password},</if>
        <if test="usernameS!=null">username=#{username}</if>
    </set>
    where email=#{email}
</update>
  1. update和where语句是在set标签之外的,内部只有原SQL的set语句的内容
  2. 每一句if标签中的内容要加上逗号,除了最后一句
foreach标签

循环遍历:比如批量删除,批量添加之类的

<select id="selectPostIn" resultType="User">
    select * from user where email in 
    <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>
  1. 此处的foreach由于组装in语句:in语句表示条件值只要在一个集合之内全部取出(这个集合就是由foreach组成的)
  2. foreach 的原理,将传入的list中的内容提取出来,可以加入开始符号,结束符号和分隔符,最后组装成一个字符串(SQL接受的是字符串,直接传入集合是不能被识别的)
  3. collection是传入的集合,item是集合的元素,index是集合的下标,open是开始字符,close是结束字符,separator是分隔符
  4. 最后出现的就是(item1,item2…)这样一个字符串
like 模糊搜索
select * from user like '%e%';

like的用法:用于模糊搜索:表示包含的意思,在字符串当中需要将字符用%包含

<select id="selectLike" resultType="User" parameterType="String">
    select * from user where username like "%"#{keyword}"%"
</select>
  1. 在传入参数时,使用双引号将#包含起来(#会自动添加单引号)

Java map:相当于是键值对:一个名字对应一个对象或者是集合(可以用于多种参数(包含集合)的传入:使得mybatis通过字符串引用变量

//给map中添加元素
Map<String, String> map = new HashMap<String,String>();
map.put("邓超", "孙俪");
map.put("李晨", "范冰冰");
map.put("刘德华", "柳岩");

综合查询(往往传入的参数是map类型的参数)

<select id="selectTogether" parameterType="Map" resultType="User">
    select * from user where username in
    <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
        #{item}
    </foreach>
    and username like "%"#{keyword}"%"
</select>
public List<User> selectTogether(){
    Map<String,Object> map = new HashMap<>();
    ArrayList<String> list = new ArrayList<>();
    list.add("eric");
    list.add("jinkens");
    map.put("list", list);
    map.put("keyword", "e");
    SqlSession sqlSession = UserDao.getFactory().openSession();
    return sqlSession.selectList("selectTogether", map);
}
  1. 传入的是map类型的键值对:list和一个集合类对应,keyword和一个String配对
  2. 搜出来的是username在eric,jinkens内且username包含”e“

多表查询

<resultMap id="User_CVE" type="User">
    <id property="username" column="username"/>
    <result property="email" column="email"/>
    <result property="password" column="password"/>
    <association property="cve" javaType="CVE">
        <id property="cve_id" column="vul_id"/>
        <result property="category" column="vul_category"/>
        <result property="desc" column="description"/>
    </association>
</resultMap>
public class User {
    private String email;
    private String password;
    private String username;
    private CVE cve;
}

public class CVE {
    private String cve_id;
    private String category;
    private String desc;

}
  1. resultMap的type指最大的一个类(User类当中包含了CVE类的一个成员属性)
  2. association用在成员属性是一个自定义类(将数据库的列与成员属性中的成员属性进行链接)

第二种查询方式

<select id="selectCveUser2" resultMap="User_cve2">
        select email,cve_id from user_cve
    </select>
    <select id="selectCVEbyCveid" parameterType="String" resultMap="CVE">
        select * from text_data1 where vul_id=#{cve_id}
    </select>

    <resultMap id="CVE" type="CVE">
        <id property="cve_id" column="vul_id"/>
        <result property="desc" column="description"/>
        <result property="category" column="vul_category"/>
    </resultMap>

    <resultMap id="User_cve2" type="User">
        <result property="email" column="email"/>
        <association property="cve" column="cve_id" select="selectCVEbyCveid" javaType="CVE">
            <id property="cve_id" column="vul_id"/>
            <result property="category" column="vul_category"/>
            <result property="desc" column="description"/>
        </association>
    </resultMap>
  1. 目的:根据第一次查询出来的cve_id查询出所有的漏洞信息,根据第二次查询的信息进行组装association
  2. resultMap中的association的colum是第二次查询的根据(会将cve_id输入到第二次查询当中):根据第二次查询的结果组装association
  3. 第一次查询是最外层,是第二次查询的根据

假设类成员属性的名称和字段名称不同则也必须用resultMap,不能直接用resultType

Mybatis动态代理机制

一般在DAO层需要调用mapper文件当中的SQL语句时,需要自己复制上命名空间(namespace)以及SQL的id

  1. 根据mapper的文件创建一个接口(接口名字和mapper文件的名字完全相同:每一个mapper文件都可以创建代理)
//动态代理对应的接口
public interface UserMapper {
    public List<User> selectUser();

    public User selectUserByEmail(String email);
}
  1. 接口中的方法需要和mapper文件当中SQL语句的id相同
  2. 在DAO层当中需要获取到代理的接口并且会自动实现接口并创建对象
public User selectUserByEmail(String email){
        SqlSession sqlSession = UserDao.getFactory().openSession();
        //创建动态代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);          //会自动将接口实现并创建一个对象
        User user = userMapper.selectUserByEmail(email);
        sqlSession.close();
        return user;
    }

懒加载

resultMap当中association和collection标签具有延迟加载的功能,因为不一定这条查询语句就会被使用,在关联查询时回先加载著信息,使用关联信息的时候再加载关联信息(只适用于嵌套查询)

<setting name="lazyLoadingEnabled" value="true"/>         <!-- 开启懒加载-->
<setting name="aggressiveLazyLoading" value="false"/>     <!-- 设置为不积极的懒加载,按需求进行加载-->
  1. 在配置xml的settings当中进行配置
  2. 积极懒加载:如果加载就会自动加载所有同级别的信息(指的是同级别的内层查询)

maven的使用

maven就是套在web项目外层,并且使用pom.xml文件来帮助导入jar包的工具

maven的三种仓库
  1. 本地仓库:存储在本地磁盘(通过setting.xml更改仓库目录)
  2. 远程仓库:使用国内镜像,连接互联网上的仓库
  3. Maven中央仓库:Maven团队维护的jar包仓库

检索的顺序:本地仓库-远程仓库-中央仓库

配置本地仓库

通过settings.xml 更改本地仓库localRepository

<localRepository>E:\maven\repository</localRepository>
配置阿里云镜像远程仓库
<mirrors>
  <mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
  </mirror>
</mirrors>
maven项目添加jar(添加依赖)
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.13</version>
</dependency>

依赖的信息可以从maven中央仓库进行获取

groupId:是项目组织唯一的标识符,实际对应JAVA的包的结构,是main目录里java的目录结构

artifactId:就是项目的唯一的标识符,实际对应项目的名称,就是项目根目录的名称

version:版本号 后缀为release:代表稳定的版本

scope: 默认的依赖范围是compile

​ 1、test范围指的是测试范围有效,在编译和打包时都不会使用这个依赖

​ 2、compile范围指的是编译范围有效,在编译和打包时都会将依赖存储进去

​ 3、provided依赖:在编译和测试的过程有效,最后生成war包时不会加入,诸如:servlet-api,因为servlet-api,tomcat等web服务器已经存在了,如果再打包会冲突

​ 4、runtime在运行的时候依赖,在编译的时候不依赖

在pom.xml当中添加完依赖之后点击maven change即可自动导入

创建Maven项目
  1. 选定模板时注意选择archtype-webapp
  2. 需要选定一个文件夹作为source boot
  3. 在打包的过程当中,maven默认只会打包java源文件:需要在pom.xml中加入如下代码自动打包xml和properties
<resources>
  <resource>
    <directory>${basedir}/src/main/com/java/mapper</directory>
    <includes>
      <include>**/*.xml</include>
      <include>**/*.properties</include>
    </includes>
  </resource>
</resources>

所有配置文件全部放在和java文件夹同级的地方并设置为source boot

maven创建servlet

需要在pom.xml当中导入相应的依赖

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <scope>provided</scope>
</dependency>
maven当中使用EL和JSTL

web.xml当中的配置有问题:使用的webApp版本太低

<?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">
</web-app>

将此段xml配置信息取代原web.xml当中的代码

Spring框架

Spring框架的引入

spring是一个非常活跃的开源框架。基于IOC和aop来构架多层javaEE系统,以帮助分离项目组件之间的依赖关系(根本目的:解除耦合度)

底层: 工厂模式+xml(可以用于帮助创建对象并注入到需要的地方)

耦合之处:在连接DAO和servlet(控制层)的service层(写对DAO层调用出来的数据的逻辑处理)当中往往需要创建DAO的对象(DAO的成员方法中封装着利用sqlsession调用SQL的语句)

方法:创建一个工厂类,将service中的创建对象语句固定,由工厂类语句决定创建什么类型的对象,再次由XML文件解除工厂类和DAO层的耦合度,工厂类将读取XML文件再根据xml文件决定创建对象的类型

xml中的bean标签:表示对象的意思(第一句话是创建一个DAO对象,第二句话是注入并赋值给stuDao属性)

<bean ID="myStuDao" class="com.test.dao.OracleStuDao">
<bean ID="stuService" class="com.test.service">
	<property name="stuDao" ref="myStuDao"/>    
</bean>

从而在service中只需要存在一个Dao的对象引用就可以,不需要创建对象

IOC和DI

IOC (Inverse of Control) :控制反转(原来创建对象(DAO对象)的权利在service层当中,现在将这个权利剥夺,并交给工厂类(是降低对象之间的耦合关系的设计思想

将service层中的new语句取消,只留下对象引用:过程是程序读取Spring配置文件,获取需要创建的bean对象

DI(Dependency injection):依赖注入(创建对象实例时,同时为这个对象注入它所依赖的属性)

<bean ID="stuService" class="com.test.service">
	<property name="stuDao" ref="myStuDao"/>    
</bean>

总结:控制反转的实现方式就是依赖注入

Spring框架的功能

  1. Spring IOC:能够帮我们根据配置文件创建及组装对象之间的依赖关系

  2. Spring AOP(面向切面编程):能够帮助我们无耦合的实现日志记录,性能统计,安全控制

    在某一个层当中(比如DAO层)插入一条打印信息的语句(同样有Spring进行添加)

  3. spring能够非常简单的帮我们管理数据库事务

  4. spring提供了与第三方数据访问框架无缝连接,比如Hibernate,mybatis,而且自己也提供了一套jdbc模板来用来数据的访问

  5. spring还提供了与第三方web框架的无缝连接,比如structs,并且自己也提供了一套springMVC框架,来方便web层搭建

  6. spring能方便的与javaEE技术整合,比如Java mail,任务调度,还可以与其它技术整合,比如缓存.

Spring组成

spring-overview
Spring核心jar包
  1. spring-core:依赖注入IOC与DI的最基本实现

  2. spring-beans:Bean工厂与bean的装配

  3. spring-context:spring的context上下文即IOC容器

  4. spring-context-support:Spring context的扩展支持,用于MVC方面

  5. spring-expression:spring表达式语言

Spring入门程序

导入Spring框架所需要的jar包

分别导入上述的Spring核心的jar包

Spring core

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

Spring Beans

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

Spring context

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

Spring context support

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

Spring expression

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>
创建Spring配置文件
  1. 创建一个文件夹,并设置为resource boot:将会读取xml配置文件
  2. 创建xml configuration的Spring config
  3. 编写bean节点用于创建对象
<bean id="userCveDao_01" class="DAO.UserCveDao"/>

class属性是类的全类名

  1. 获取IOC容器(ApplicationContext类),通过getBean方法获取对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
UserCveDao userCveDao = applicationContext.getBean("userCveDao_01",UserCveDao.class);

这只是暂时用于测试的方法,DI能够直接注入到所需要的成员属性

bean标签的使用

  1. id和name:通过两者都可以利用getBean来获取对象(方式完全一样)
UserCveDao userCveDao = applicationContext.getBean("userCveDao_01",UserCveDao.class);
  1. scope:singletype和prototype:单例模式和多例模式:同一个bean在多次获取时获取的对象是否是同一个对象(设置对象的生成方式

  2. lazy-init:更改创建对象的时间:

    lazy-init=“false” :默认值,不延迟创建,即在创建IOC容器的时候就创建对象

    lazy-init=“true” :延迟初始化,在使用getBean的时候才会创建对象

  3. 初始化/销毁:init-method=“init” destroy-method=“destroy”(确定初始化以及销毁的方法)

    生命周期中的构造函数之后其他方法之前调用

<bean id="drink_01" name="drink_02" scope="singleton"
      lazy-init="true"
      init-method="init" destroy-method="destroy"
      class="com.test.pojo.Drink" />

Spring创建对象的三种方式

通过构造方法创建对象(默认调用的是无参构造方法)
<bean id="drink_01"  class="com.test.pojo.Drink"  />

利用有参数构造方法创建对象

public class SequenceFile {
  private int dependency1;
  private String dependency2;

  public SequenceFile(int dependency1, String dependency2) {
    this.dependency1 = dependency1;
    this.dependency2 = dependency2;
  }
}
<bean id="sequenceFile" class="com.market.SequenceFile">
  <constructor-arg value="abc" index="1" type="String"/>
  <constructor-arg value="123" index="0" type="int"/>
</bean>
通过静态方法创建对象(不允许调用构造方法)

往往这种使用静态工厂创建对象的类都属于第三方jar包提供,比如SqlSessionFactory需要SqlSessionFactoryBuilder进行build

public class DrinkFactory2 {
    public static Drink createDrink(){
        return new Drink();
    }
}
<bean id="drink_04"  class="com.test.drinkFactory" factory-method="createDrink" />
  1. factory-method:表示工厂对象build的方法
  2. class:这里指的是工厂的全类名(不是要创建对象的全类名)
通过非静态方法创建对象(不允许调用构造方法)
public class DrinkFactory2 {
    public  Drink createDrink(){
        return new Drink();
    }
}
<!-- 1.创建工厂对象 -->
<bean id="drinkFactory" class="com.test.factory.DrinkFactory2" />
<!-- 2. 调用工厂对象中的方法 -->
<bean id="drink_04"  factory-bean="drinkFactory" factory-method="createDrink" />

在xml文件中 先创建工厂对象,再调用工厂中的方法来创建我们需要的对象

  1. 创建工厂对象时,就是直接调用构造方法
  2. factory-bean:所属工厂方法的bean
  3. factory-method:调用工厂当中的创建方法

依赖注入(DI)

将创建的对象所依赖的属性进行注入

通过property标签进行注入(直接注入到属性当中)
public class Drink {

    private String name;

    private String sugar;

    private float price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSugar() {
        return sugar;
    }

    public void setSugar(String sugar) {
        this.sugar = sugar;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public Drink() {
        System.out.println("创建一杯饮料");
    }
}
<bean id="drink_01" class="com.test.pojo.Drink" >
    <property name="name" value="西瓜汁" />
    <property name="price" value="18" />
    <property name="sugar" value="半糖" />
</bean>
构造函数注入

public class CVE {
    private String cve_id;
    private String category;
    private String desc;

    public CVE(String cve_id, String category, String desc) {
        this.cve_id = cve_id;
        this.category = category;
        this.desc = desc;
    }

    public String getCve_id() {
        return cve_id;
    }

    public String getCategory() {
        return category;
    }

    public String getDesc() {
        return desc;
    }

    public void setCve_id(String cve_id) {
        this.cve_id = cve_id;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
<bean id="CVE_01" class="test.CVE">
    <constructor-arg index="0" value="CVE-1999-1431"/>
    <constructor-arg index="1" value="设计错误"/>
    <constructor-arg index="2" value="ZAK in Appstation mode allows users to bypass the Run only allowed apps policy by starting
    Explorer from Office 97 applications (such as Word), installing software into the TEMP directory
    , and changing the name to that for an allowed application, such as Winword.exe."/>
</bean>

创建复杂对象:包含DAO类型成员属性的service对象的创建

public class UserCveService {
    private UserCveDao dao;

    public UserCveDao getDao() {
        return dao;
    }

    public void setDao(UserCveDao dao) {
        this.dao = dao;
    }
    
    public void test(){
        List<User> list = dao.selectMoreTable2();
        for (User user:list) {
            user.tell();
        }
    }
}
<bean id="userCveDao_01" class="DAO.UserCveDao"/>
<bean id="userCveService_01" class="service.UserCveService">
    <property name="dao" ref="userCveDao_01"/>
</bean>
  1. 先创建成员变量的对象(DAO对象)
  2. 创建复杂对象(通过ref属性,将之前创建的Bean注入)
P空间注入
  1. 引入P空间

    xmlns:p=“http://www.springframework.org/schema/p”

    将这句语句加在beans节点下的属性当中:

    <?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:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>
    
  2. 使用P空间注入

<bean id="CVE_p" class="test.CVE" 
          p:category="设计错误" 
          p:cve_id="CVE-1999-1431" 
          p:desc="ZAK in Appstation mode allows users to bypass the Run only allowed apps policy by starting.Explorer from Office 97 applications (such as Word), installing software into the TEMP directory, and changing the name to that for an allowed application, such as Winword.exe."/>

<!-- 使用引用变量赋值-->
    <bean id="userCveDao_01" class="DAO.UserCveDao"/>
    <bean id="userCveService_01" class="service.UserCveService" p:dao-ref="userCveDao_01"/>
复杂类型注入
public class TestBean_01 {
    private int[] array;
    private User[] arrayUser;
    private List<String> stringList;
    private Properties properties;
    private Map<String, User> map;
}
<bean id="testBean" class="test.TestBean_01">
    <property name="array">
        <array>
            <value type="int">1</value>
            <value type="int">2</value>
        </array>
    </property>
    
    <property name="arrayUser">
        <array>
            <ref bean="user_02"/>
        </array>
    </property>
    
    <property name="stringList">
        <list>
            <value type="java.lang.String">tom</value>
            <value type="java.lang.String">jack</value>
        </list>
    </property>
    
    <property name="map">
        <map>
            <entry key="first" value-ref="user_02"/>
        </map>
    </property>

    <property name="properties">
        <props>
            <prop key="driver">com.mysql.jdbc.Driver</prop>
            <prop key="url">jdbc:mysql://localhost:3306/webproject?characterEncoding=utf-8&amp;serverTimezone=GMT</prop>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
        </props>
    </property>
</bean>
Spel方式注入

Spring expression language:注入的值不再是上述的固定值:比如从DAO层传入

Spel产生的都是对象,不会产生方法

比如如果只是引入对象中的某个属性 可以 用#{}

<bean id="outSeller_05" class="com.test.pojo.OutSeller" p:type="饿了么"
          p:drink-ref="drink_05" />
          
<bean id="outSeller_06" class="com.test.pojo.OutSeller">
      <property name="type" value="#{outSeller_05.type}" />
       <property name="drink" ref="drink_05" />
</bean>
<!-- 利用成员方法注入:先创建对象,再利用spel语句-->
<bean id="user_02" class="test.User">
    <constructor-arg index="0" value=""/>
    <constructor-arg index="1" value=""/>
</bean>
<bean id="testSpel_02" class="test.TestSpel">
    <constructor-arg index="0" ref="user_02"/>
</bean>
<bean id="testSpel_01" class="test.TestSpel_01">
    <property name="user" value="#{testSpel_02.getNormalUser()}"/>
</bean>

<!-- 利用静态方法注入-->
<bean id="testSpel_03" class="test.TestSpel_01">
    <property name="user" value="#{T(test.TestSpel).getStaticUser()}"/>
</bean>
  1. 访问成员属性: #{对象.属性名}

  2. 访问静态方法: #{T(包名.类名).方法名([参数])}

  3. 访问成员方法: #{对象.方法名()}

注解方式注入

案例目的:创建userCveService和userCveDao对象,并将dao对象注入到service对象当中

注解只能用在自己写的实用类,并不能用在导入的类,因为注解都是写在类的源代码上方的

1. 配置注解扫描

注解信息写在Spring框架的配置文件当中,需要指定撰写注解的类的包名,会全部进行扫描

<?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 http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 开启注解扫描:扫描com.test包以及所有子包中的文件-->
    <context:component-scan base-package="com.test" />
</beans>
<context:component-scan base-package="com.test" />

表明的是使用了注解ioc方式的包(context写在beans节点之下)

2. 创建对象的注解
//创建一个对象(组件)
@Component
//创建service层对象,没有什么特殊的含义的对象,比如DAO对象
@Service
//创建控制层对象
@Controller
//默认会创建一个DrinkService的对象 对象的名字为drinkService (类名的首字母小写)
@Service
//也可以设置自己制定的对象名
@Service("myDrinkService")
public class DrinkService implements IDrinkService {
    
}

创建对象的注解写的位置就是这个类的声明处

3. 用于依赖注入的注解

注解方式注入可以不需要get,set方法,但是配置文件的方式需要

依赖注入的注解同样是写在创建对象的类的声明处

依赖注入之前,这些对象都需要被创建

//根据类型自动注入
@Autowired
//如果满足自动注入的对象有多个,可以通过@Qualifier()设置具体的对象名
@Qualifier("对象名")
//根据对象名注入,作用相当于@Autowired+@Qualifier("对象名")   
@Resource(name="对象名")
//自动注入
@Autowired
//指定注入的对象(如果满足注入对象有多个的时候)
@Qualifier("oracleDrinkDao")
private IDrinkDao drinkDao;

public IDrinkDao getDrinkDao() {
    return drinkDao;
}

//也可以在set方法上设置自动注入,也可以不需要set方法
public void setDrinkDao(IDrinkDao drinkDao) {
   this.drinkDao = drinkDao;
}
@Resource(name="oracleDrinkDao") 
//相当于autowired+qualifier
private IDrinkDao drinkDao;

public IDrinkDao getDrinkDao() {
    return drinkDao;
}

public void setDrinkDao(IDrinkDao drinkDao) {
   this.drinkDao = drinkDao;
}
4. 其他注解

创建对象需要注入普通类型:String:使用@Value标签

@Component
public class User {
    
    @Value("894962134@qq.com")
    private String email;
    @Value("123456")
    private String password;
    @Value("eric")
    private String username;
    
    public String getEmail() {
        return email;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

设置为多例模式:@Scope(指的是利用工具包获取bean时候获取的是否是同一对象

设置对象的作用域,默认是单例,可以设置为多例模式@Scope(scopeName=“prototype”)

设置是否懒加载:@Lazy

默认是非懒加载,设置 @Lazy代表懒加载,前提是单例模式

//@Scope(scopeName ="prototype" )
//设置是否是懒加载  默认是false 前提是单例
@Lazy
@Component
public class Drink {
    @Value("橙汁")
    private String name;
}

SpringAOP

AOP介绍

AOP(Aspect Oriented program):面向切面编程

基本开发方式(由一名程序员开发一个模块的control,service和DAO层,一个纵向的过程)

aop

问题:假设需要在service层需要添加一个权限判断,则需要在所有的service进行更改

AOP:将需要修改的代码写在外面,然后通过切面切入一个层当中(相当于对某一个层的所有模块进行了一个统一的修改)

AOP应用点(并不影响原来的业务结构):权限认证、日志、事务

  1. 核心关注点

    纵向的业务流程,每一个模块之间都不相同

  2. 横切关注点

    与业务逻辑关系不大,发生在核心关注点的多处出现,各处基本相似,AOP就是将横切关注点利用“横切”的技术剖解并封装到一个可以重用的对象内部(切面),再将其切入

  3. 连接点(Joinpoint)

    在一个模块的service中会有很多的方法,连接点指的是可以切入的点(程序执行的某一个位置:Spring支持方法连接点:方法调用前,方法调用后,方法抛出异常时

  4. 切点(Pointcut)

    切点指的就是特定的连接点,也就是需要切入的连接点(比如add方法的方法调用前)

  5. 增强(Advice)

    织入目标程序连接点(切点)的一段程序代码,封装在一个类,也称为增强类

  6. 目标对象(target)

    指的是织入的连接点所属的对象(比如图中的三个service对象)

  7. 织入(Weaving)

    将增强添加到目标连接点(切点)得到一个过程

    编译期织入:使用特殊的Java编译器

    类装载期织入:使用特殊的类装载器

    动态代理织入:在运行期为目标类添加增强生成子类的方式、

    Spring采用动态代理织入,而AspectJ采用编译期织入和类装载器织入.

  8. 代理(proxy)

    目标对象的类被织入了增强之后,会产生一个结果类(织入并不是直接修改代码,而是重新写了另外一个类),这个结果类就是融合了原有类的逻辑以及增强类的增强的代理类(代理类根据不同的代理模式,可能是原有类的子类也有可能具有相同的接口,可以用相同的方式调用)

  9. 切面(aspect)

    切面类:在增强类的基础上增加了切点的定义(增强类可以切入到任意切点当中,切面类增加了切点的定义,就限制了切入的位置)

  10. 通知类型(相当于就是连接点去掉了具体的方法)

    //前置通知:目标方法运行之前调用
    //成功返回通知(后置通知)(如果出现异常不会调用):在目标方法运行之后调用
    //环绕通知:在目标方法之前和之后都调用,还可以替代原方法
    //异常拦截通知:如果出现异常,就会调用
    //后置通知(无论是否出现 异常都会调用):在目标方法运行之后调用
    
代理模式
静态代理

原理:创建一个代理类实现目标类的接口,在代理类中包含目标类的对象

  1. 创建一个接口,由目标类实现

    public interface IUserService {
        public void tell();
    }
    
  2. 目标类实现接口

    import com.test.staticproxy.IUserService;
    
    public class UserService  implements IUserService {
    
        @Override
        public void tell() {
              System.out.println("hello");
        }
    }
    
  3. 创建代理类,实现同样的接口,其中包含目标类属性

    public class UserProxy implements IUserService {
    
        private IUserService userService=new UserService();
    
        @Override
        public void tell() {
            System.out.println("代理给代理对象加的内容");
            userService.tell();
            System.out.println("代理给代理对象加的内容");
        }
    }
    

静态代理:缺点在于代理的是固定的对象(对象被放在代理类的属性当中)

动态代理(Spring实现AOP的底层原理)

静态代理代理的是固定对象,可以用动态代理实现代理不同的对象

JDK自带的代理方式

原理:通过JDK自带的Proxy类来创建一个代理对象,代理类实现目标类得到接口

前提:目标对象必须存在一个接口

  1. 必须存在的目标对象的接口

    package service;
    
    public interface IService {
        void test();
        void tell();
    }
    
  2. 实现接口的目标对象

    package service;
    
    import DAO.UserCveDao;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import org.springframework.stereotype.Service;
    import test.User;
    
    import java.util.List;
    
    @Service
    public class UserCveService implements IService {
    
        @Autowired
        private UserCveDao dao;
    
        @Override
        public void test(){
            List<User> list = dao.selectMoreTable2();
            for (User user:list) {
                user.tell();
            }
        }
    
        @Override
        public void tell() {
            System.out.println("hello");
        }
    
        public UserCveDao getDao() {
            return dao;
        }
    
        public void setDao(UserCveDao dao) {
            this.dao = dao;
        }
    }
    
  3. 创建代理类生成器(使用的接口是InvocationHandler,其中需要实现的方法是invoke)

    package proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class JdkHandler implements InvocationHandler {
        Object subject;                        //用于存放目标对象
    
        public JdkHandler(Object subject){
            this.subject = subject;            //构造方法传入目标对象
        }
    	//生成一个代理对象并进行返回,目标对象是subject
        public static Object bind(Object subject){                             
            return Proxy.newProxyInstance(JdkHandler.class.getClassLoader(),        //加载字节码文件:获取subject和invoke方法
                    subject.getClass().getInterfaces(),                            //获取目标对象的接口,实现的代理类实现该接口
                    new JdkHandler(subject));                                      //传入生成器对象,来调用invoke方法
        }
    
        //bind创建的对象只是实现了目标对象的接口,方法体当中做什么并没有指明
        //invoke方法,通过反射的方式可以调用原目标方法,并在之前之后自定义
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("打印日志");
    
            //调用原目标方法
            Object object = method.invoke(subject, args);
            return object;
        }
    }
    
  4. 创建代理对象并进行测试

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import proxy.JdkHandler;
    import service.IService;
    import service.UserCveService;
    
    public class TestProxy {
        @Test
        public void test(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContextTag.xml");
            UserCveService userCveService = applicationContext.getBean("userCveService",UserCveService.class);       //完成控制反转的过程并实现依赖注入如
            IService service = (IService) JdkHandler.bind(userCveService);
            service.test();
            System.out.println("done");
            service.tell();
        }
    }
    
    //这里的切入,会将invoke中的增强切入到目标对象的接口所写到的所有方法中
    //method会随着代理对象调用方法的改变而改变
    
Cglib方式

原理:通过创建目标类的子类,作为代理对象,在子类当中拦截目标类的方法并进行加强

不需要目标对象存在接口,改善JDK自带代理方式

  1. 导入Cglib所需要的jar包

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>3.2.4</version>
    </dependency>
    
  2. 创建目标类

    package service;
    
    import DAO.UserCveDao;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import org.springframework.stereotype.Service;
    import test.User;
    
    import java.util.List;
    
    public class UserCveService {
    
        private UserCveDao dao = new UserCveDao();
    
        @Override
        public void test(){
            List<User> list = dao.selectMoreTable2();
            for (User user:list) {
                user.tell();
            }
        }
    
        @Override
        public void tell() {
            System.out.println("hello");
        }
    
        public UserCveDao getDao() {
            return dao;
        }
    
        public void setDao(UserCveDao dao) {
            this.dao = dao;
        }
    }
    
    
  3. 创建一个代理生成器(实现的接口:MethodInterceptor实现intercept方法,用于拦截方法)

    package proxy;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class MyCglib implements MethodInterceptor {
        //创建一个对象生成器
        private Enhancer enhancer = new Enhancer();
    
    
        public Object getProxy(Class aClass){                   //传入的不再是目标对象,而是目标对象的类的字节码文件
            //设置目标对象的类作为生成代理类的父类
            enhancer.setSuperclass(aClass);
            //设置回调函数,目的在于调用拦截器的方法
            enhancer.setCallback(this);
            //创建子类对象并进行返回
            return enhancer.create();
        }
    
        //实现接口当中的方法,用于拦截方法
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("打印日志");
            //调用代理对象的父类同名的方法,代理对象调用不同的方法
            Object result= methodProxy.invokeSuper(o,objects);
            return result;
        }
    }
    
  4. 进行测试

    import org.junit.Test;
    import proxy.MyCglib;
    import service.UserCveService;
    
    public class TestCglibProxy {
        @Test
        public void test(){
            MyCglib myCglib = new MyCglib();
            UserCveService userCveService = (UserCveService) myCglib.getProxy(UserCveService.class);
            userCveService.test();
        }
    }
    
切入点表达式

用于定位切点所在的方法

execution([修饰符] 返回值类型 包名.类名.方法名(参数))
<!-- []表示可以省略-->
execution( public void com.test.service.impl.UsersService.add() )
  1. 参数列表可以进行设置…表示有无参数均可

    `<aop:pointcut   expression="execution( *com.test.service.impl.UsersService.add(..))" id="pt"/>
    
  2. 找到service包UserCveService所有作用域类型的test方法

    `<aop:pointcut   expression="execution(
    * service.UserCveService.test())" id="pt"/>
    
  3. 类名可以使用*号,表示任意类

    <aop:pointcut   expression="execution( * com..*.add(..))" id="pt"/>
    
  4. 使用…来表示当前包,及其子包

    <aop:pointcut   expression="execution( * com..UsersService.add(..))"  id="pt"/>
    
  5. 类名也可以使用 * 加后缀,表示这个后缀的所有类

    <aop:pointcut   expression="execution( * com..*Service.add(..))"  id="pt"/>
    
  6. 方法名可以使用*号,表示任意方法

    <aop:pointcut   expression="execution( * com..*.*(..))" id="pt"/>
    
  7. 拦截所有save开头的方法

    <aop:pointcut   expression="execution(* save*(..))"`id="pt"/>
    
  8. 参数列表可以使用 * , 表示可以是任何的数据类型,但必须有参数

    <aop:pointcut   expression="execution( *com.test.service.impl.UsersService.add(*))" id="pt"/>
    
  9. 全通配方式execution( * .* ( … ) )

    <aop:pointcut   expression="execution(public * *(..))"`id="pt"/>
    
SpringAOP使用
通过配置文件织入
  1. 导入相应和AOP相关的jar包

        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>4.3.18.RELEASE</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aspects</artifactId>
          <version>4.3.18.RELEASE</version>
        </dependency>
    
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.8.10</version>
        </dependency>
        
        <dependency>
          <groupId>aopalliance</groupId>
          <artifactId>aopalliance</artifactId>
          <version>1.0</version>
        </dependency>
    
  2. 编写增强类

    package advice;
    
    import java.util.Date;
    
    public class MyAdvice {
        //将这个增强方法的test方法之前
        public void before(){
            System.out.println("开始时间"+new Date());
        }
        //将这个增强方法的test方法之后
        public void after(){
            System.out.println("结束时间"+new Date());
        }
    }
    
  3. 编写配置文件,创建增强对象,并进行织入

    <?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!-- 创建增强类 -->
        <bean id="myAdvice" class="advice.MyAdvice"/>
        <!-- 进行织入操作 -->
        <aop:config>
            <!-- 定义切点-->
            <aop:pointcut id="testBefore" expression="execution(* service.UserCveService.test())"/>
            <!-- 切入切点-->
            <aop:aspect ref="myAdvice">
                <aop:before method="before" pointcut-ref="testBefore"/>        <!-- 确认增强类要织入的方法-->
            </aop:aspect>
        </aop:config>
    </beans>
    
  4. 测试aop执行

    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import service.IService;
    
    public class TestAopXml {
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext_aop.xml");
            IService service = context.getBean("userCveService",IService.class);
            //获取的是目标对象的接口,底层是利用JDK自带代理方式,不是Cglib
            service.test();
        }
    }
    
AOP的五种通知类型

通知类型:织入时增强相对于目标方法的相对位置:每个通知类型对应一种标签,写在aop:aspect节点下

  1. aop:before通知:在目标方法调用之前执行增强,目标方法会执行

  2. aop:around通知:在目标方法调用时执行,可以放行目标方法(执行目标方法),也可以不放行(相当于直接替代)

    在增强类当中加入的around方法需要考虑是否加上point.proceed(),决定是否放行

     public void round(ProceedingJoinPoint point) throws Throwable {
            //查询方法
            System.out.println( "准备在目标方法中添加环绕通知");
         if(false)
             point.proceed(); //放行目标方法
    }
    
    //环绕通知:用增强代码替换目标方法
    public Object around(ProceedingJoinPoint point) throws Throwable {
              System.out.println("查询所有用户信息");
              return point.proceed();// 等价于userDao.select()
    }
    
  3. aop:after通知:在目标方法调用之后执行增强,目标方法会执行

  4. aop:afterReturning通知:目标方法成功执行时执行增强

  5. aop:afterException通知:目标方法抛出异常后执行

通过注解的方式注入

注解内容:切点的定义,织入切点通知类型

  1. 增强类当中的增强方法的注解:包括切点表达式指出了切点

    五种通知类型代表了五种注解类型

    package advice;
    
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Before;
    
    import java.util.Date;
    @Aspect
    public class MyAdvice {
        @Before("execution(* service.UserCveService.test())")
        //将这个增强方法的test方法之前
        public void before(){
            System.out.println("开始时间"+new Date());
        }
        @After("execution(* service.UserCveService.test())")
        //将这个增强方法的test方法之后
        public void after(){
            System.out.println("结束时间"+new Date());
        }
    }
    
  2. 第二种注解方式:同一个切点需要多次使用

    package advice;
    
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    import java.util.Date;
    @Aspect
    public class MyAdvice {
        @Pointcut("execution(* service.UserCveService.test())")
        public void pointCut(){ }
    
        @Before("MyAdvice.pointCut()")
        //将这个增强方法的test方法之前
        public void before(){
            System.out.println("开始时间"+new Date());
        }
        @After("MyAdvice.pointCut()")
        //将这个增强方法的test方法之后
        public void after(){
            System.out.println("结束时间"+new Date());
        }
    }
    
    
  3. 配置文件开启自动代理

    <?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="service"/>
        <context:component-scan base-package="DAO"/>
        <!-- 创建切面类对象-->
        <bean id="myAdvice" class="advice.MyAdvice"/>
        <!-- 开启aop注解的分析读取,开启自动代理-->
        <aop:aspectj-autoproxy/>
    </beans>
    
什么是事务

事务是不可分割的一个并发控制单元,以begin/start transaction开始,以commit或rollback结束

commit:提交,表示事务成功进行,数据库进行更新

rollback:回滚,表示事务进行失败,撤销事务中的一切操作

案例:购物车购买商品后,账户余额减 少,仓库商品数量减少,两个操作必须都进行或者都不进行,二者即归为同一事务,若只有其中之一进行则会造成数据库的重大错误

事务的特征和隔离级别

事务的特征ACID

  1. 原子性:事务是原子工作单位,不可分割
  2. 一致性:事务完成之后,数据必须保持一致的状态,保持完整性
  3. 隔离性:一个事务的执行不能被其他的事务影响,解决并发问题
  4. 持久性:事务一旦提交,会永久的储存,此时回滚已经没有用处

事务的隔离级别(事务的并发问题)

  1. 脏读:一个事务读取到了另一个事务未提交(回滚)的数据操作结果[读取的时间太早]
  2. 不可重复读(虚读):一个事务对同一行数据读取了两次,得到不同的结果(另一个事务进行了更新操作)
  3. 幻读:事务操作过程中进行两次查询,第二次查询包含第一次查询中未出现的数据,或者缺少第一次查询的部分数据(另一个事务进行了插入或者删除操作)
  1. 读未提交:最低级别,以上情况都无法保证不出现
  2. 读已提交:可避免脏读
  3. 可重复读:不能避免幻读的情况,一个事务正在使用一条记录并且未结束,不允许其他事务修改该记录(默认)
  4. 串行化读:事务一个一个执行,避免所有情况,整张表都不能进行修改,执行效率极慢
Spring事务的传播行为

案例:另一个业务逻辑需要调用事务当中的方法,会不会导致开启事务

Spring中的传播行为

PROPAGATION_REQUIRED:当前方法必须运行在事务中,如果事务不存在就开启事务(第三方调用方法会开启新的事务)

PROPAGATION_SUPPORTS:表示方法不需要事务的上下文,但是如果事务已经开启,方法在事务中运行(第三方调用不开新事务)

PROPAGATION_MANDATORY:必须在事务中运行,如果不存在事务会抛出异常

PROPAGATION_REQUIRED_NEW:需要在新开启的事务当中运行,假设需要调用方法需要重新开启事务,原来的事务会被挂起

PROPAGATION_NOT_SUPPORTED:该方法不应该运行在事务当中,在第三方调用方法时,如果事务已经开启则将原事务挂起

PROPAGATION_NEVER:方法在被第三方调用的过程当中不应该运行在事务当中,如果有事务在运行则抛出异常

PROPAGATION_NESTED:如果已经存在事务则会在嵌套事务(嵌套一个相同的事务)当中运行,事务不存在则和REQUIRED相同

Spring管理事务

声明式事务管理,编程式事务管理(已过时)

基于@Transaction注解的事务管理
基于AOP实现事务管理(将逻辑进行增强,使其称为事务)

Spring整合mybatis

需要导入Springjdbc进行对mybatis的整合

spring创建mybatis的第三方类:sqlSessionFactory

原来的DAO中利用构造方法手动创建sqlsessionFactory对象

public UserDao() {
    InputStream inputStream = UserDao.class.getClassLoader().getResourceAsStream("mapper\\mybatis.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    this.sqlfactory = builder.build(inputStream);
}
  1. 导入jar包(包含springjdbc和springMybatis)
<!-- spring 整合 mybatis-->
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>1.3.2</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>5.2.6.RELEASE</version>
</dependency>
  1. 将mybatis.xml中的数据库配置信息转移到spring配置文件当中(手动创建时利用输入流读取了mybatis.xml文件)
<!-- Spring配置文件中写入数据库信息-->
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/webproject?serverTimezone=CST"/>
    <property name="user" value="root"/>
    <property name="password" value="123456"/>
</bean>
  1. 在配置文件当中利用bean创建sqlsessionFactory(bean的class是SqlSessionFactoryBean)
<!-- 创建sqlsessionfactory对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 链接数据源-->
    <property name="dataSource" ref="comboPooledDataSource"/>
    <!--链接mybatis配置文件-->
    <property name="configLocation" value="classpath:mapper/mybatis.xml"/>
</bean>

Spring整合mybatis消除DAO层

<!--扫描mapper映射文件,生成代理对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.test.Mapper"/>
</bean>

spring会帮助创建一个实现接口的代理对象,其功能就是DAO的功能,在service中只需要把DAO属性改成mapper接口

需要将mapper.xml文件放在java.com.test.Mapper包当中

<resources>
  <resource>
    <!-- 将Mapper的映射文件拷贝出来 -->
    <directory>src/main/java</directory>
    <includes>
      <include>**/*.xml</include>
    </includes>
    <filtering>true</filtering>
  </resource>
</resources>

SpringMVC

springMVC是web框架,用于简化用户和程序之间的数据传递

view:jsp文件 user:输入接受信息 controller:组装用户输入的信息

1368961-20180408153023520-184497993
  1. 用户发送请求至前端控制器,前端控制器接受请求(一串url)
  2. 前端控制器调用处理器映射器对url进行解析
  3. 映射器解析完毕后返回执行链(一系列的指令)
  4. 前端控制器会根据执行链,寻找到处理器适配器,由处理器适配器寻找相应的处理器进行执行
  5. 处理器执行后会返回modelAndView:数据和视图

SpringMVC的使用

  1. 导入jar包
<!-- 导入SpringMvc 需要的jar包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.3.18.RELEASE</version>
</dependency>
<!-- 配置servlet-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

<!--配置jsp的依赖 -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2</version>
    <scope>provided</scope>
</dependency>

<!-- 配置jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
  1. 创建springMVC的配置文件(SpringMVC.xml)

自己创建springMVC配置文件的模板

<?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:p="http://www.springframework.org/schema/p"
       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">
    <!-- 1. 配置  需要扫描的控制层在哪个包  -->
    <context:component-scan base-package="com.test.controller"></context:component-scan>
    <!-- 2 配置 视图解析器 中的 前缀和后缀  -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 设置前缀  -->
        <property name="prefix" value="/WEB-INF/"/>
        <!-- 设置后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
  1. 配置web.xml文件(配置前端控制器)
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
    
  <!-- 配置监听器,读取applicationContext.xml-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:SpringApplicationContext/applicationContext.xml</param-value>
  </context-param>
  <!-- 配置context 加载的监听器   -->
  <!-- 加载spring 的容器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
    
  <!-- 加入前端控制器 DispatcherServlet -->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 设置 DispatcherServlet 的参数 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMVC/springMVC.xml</param-value>
    </init-param>

    <!-- 1 启动服务器的时候就加载  -->
    <!-- 0 使用的时候再加载 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>
  1. 简单案例(单击链接,转发至reg.jsp页面)
<html>
<body>
<a href="user/reg">注册</a>
<!-- 进入user控制器的reg方法当中,在WEB-INF中的jsp只能通过控制器进行访问,不能通过链接的方式进入-->
<h2>Hello World!</h2>
</body>
</html>
package com.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/reg")
    public String reg(){
        return "reg";             //返回字符串即转发到reg.jsp页面,在springMVC.xml中配置加入前后缀
    }
}

SpringMVC的简单数据传递

RequestMapping注解:@RequestMapping(value = "/login", method = RequestMethod.POST)

value:指的是方法(控制器)的路径

method:指的是允许方法的类型

如何从jsp页面传递值给控制器

  1. 在控制器方法中加入参数request和response,相当于就是接收前端控制器给出的request和response
@RequestMapping(value = "/loginRequest", method = RequestMethod.POST)
public void loginRequest(HttpServletRequest request, HttpServletResponse response){
    String email = request.getParameter("email");
    String password = request.getParameter("password");
    System.out.println(email+password);
}
  1. 通过注解的形式@RequestParam(value = “email”),直接在方法参数当中定义
@RequestMapping(value = "/loginRequest", method = RequestMethod.POST)
public String loginRequest(@RequestParam(value = "email") String email, @RequestParam(value = "password") String password){
    boolean userFound = false;
    ArrayList<User> list = iuserService.userLoginMessage();
    for (User user:list) {
        System.out.println(user.getEmail());
        if (user.getEmail().equals(email) && user.getPassword().equals(password)){
            userFound = true;
            break;
        }
    }
    if (userFound)
        System.out.println("userFound");
    else
        System.out.println("userNotFound");
    return "account";
}

Rest和Ant风格传递参数

Rest风格

在路径使用rest风格的时候,需要在requestMapping中添加路径,在方法声明的参数当中需要用@PathVariable注解路径上的参数

<a href="User/login3/zhangsan/123">登录3</a><br/>
@RequestMapping("/login3/{aa}/{pwd}")
public String login3(@PathVariable(value="aa") String name,@PathVariable(value="pwd") String pwd)
    {
        System.out.println(name);
        System.out.println(pwd);
        return "success";
    }
Ant风格

3个通配符:**表示匹配任意路径;*表示匹配任意字符;?表示匹配一个任意字符

SpringMVC传递复杂对象(json的作用,前端传递的假设是表单)

直接在方法声明中的参数加入需要组装的一定义类:表单input和成员属性名称相同

@RequestMapping(value = "/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser){
    boolean userFound = false;
    ArrayList<User> list = iuserService.userLoginMessage();
    for (User user : list) {
        if (user.loginConfirm(loginUser)) {
            userFound = true;
            break;
        }
    }
    if (userFound)
        System.out.println("userFound");
    else
        System.out.println("userNotFound");
    return "account";
}

嵌套对象的组装(对象当中包含自定义对象,输入框写名字时用.)

<form action="user2/addUser" method="post">
	<input type="text" name="uname" />
	<input type="text" name="pwd" />
	<input type="text" name="age" />
	<input type="text" name="address.province" />
	<input type="text" name="address.city" />
	<input type="text" name="address.detailAddress" />
	<input type="submit" name="sub" value="提交" />
</form>

Model的使用

路径:服务器端向客户端(jsp,html),底层依旧是使用request的键值对

方法:存入model或者modelMap以及modelAndView,然后直接返回页面,在页面当中使用el和jstl进行取值

存放的键值对的存储对象都是写在方法的参数当中

@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser, Model model){
    boolean userFound = false;
    User userForReturn = null;    //用于登录成功后传递给主页
    ArrayList<User> list = iuserService.userLoginMessage();
    for (User user : list) {
        if (user.loginConfirm(loginUser)) {
            userFound = true;
            userForReturn = user;
            break;
        }
    }
    if (userFound) {
        System.out.println("userFound");
        model.addAttribute("loginSuccessUserInfo", userForReturn);
        return "account";
    }
    else {
        System.out.println("userNotFound");
        model.addAttribute("loginFail", "loginFailed");
        return "login";
    }
}
<span>${loginSuccessUserInfo.username}</span>

Map的使用

map和model的用法相似,只是调用的方法并不同

@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser, Map map){
    boolean userFound = false;
    User userForReturn = null;    //用于登录成功后传递给主页
    ArrayList<User> list = iuserService.userLoginMessage();
    for (User user : list) {
        if (user.loginConfirm(loginUser)) {
            userFound = true;
            userForReturn = user;
            break;
        }
    }
    if (userFound) {
        System.out.println("userFound");
        map.put("loginSuccessUserInfo", userForReturn);         //将map放入键值对,并进行传递
        return "account";
    }
    else {
        System.out.println("userNotFound");
        map.put("loginFail", "loginFailed");
        return "login";
    }
}

ModelMap的使用

ModelMap的使用方式完全相同

@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public String loginRequest(UserBasicInfo loginUser, ModelMap map){
    boolean userFound = false;
    User userForReturn = null;    //用于登录成功后传递给主页
    ArrayList<User> list = iuserService.userLoginMessage();
    for (User user : list) {
        if (user.loginConfirm(loginUser)) {
            userFound = true;
            userForReturn = user;
            break;
        }
    }
    if (userFound) {
        System.out.println("userFound");
        map.put("loginSuccessUserInfo", userForReturn);         //将map放入键值对,并进行传递
        return "account";
    }
    else {
        System.out.println("userNotFound");
        map.put("loginFail", "loginFailed");
        return "login";
    }
}

ModelAndView的使用

将所需要的页面信息和model所带的键值对全部传入ModelAndView,并返回

@RequestMapping(value = "/**/loginRequest", method = RequestMethod.POST)
public ModelAndView loginRequest2(UserBasicInfo loginUser){
    boolean userFound = false;
    User userForReturn = null;                                                 
    ModelAndView modelAndView = new ModelAndView();
    ArrayList<User> list = iuserService.userLoginMessage();
    for (User user : list) {
        if (user.loginConfirm(loginUser)) {
            userFound = true;
            userForReturn = user;
            break;
        }
    }
    if (userFound) {
        System.out.println("userFound");
        //设置modelAndView中的model键值对
        modelAndView.addObject("loginSuccessUserInfo", userForReturn);
        //设置view:所转发的页面的信息
        modelAndView.setViewName("account");
    }
    else {
        System.out.println("userNotFound");
        modelAndView.addObject("loginFail", "loginFailed");
        modelAndView.setViewName("login");
    }
    return modelAndView;
}
<c:forEach var="user" items="${userList}">
	<br>${user}</br> 
</c:forEach>

利用jstl获取后端controller传输的集合对象

SpringMVC存入session

jsp当中session使用el取值

${sessionScope.loginSuccessUserInfo.getPassword()}

利用注解的方式,将存入ModelAndView的某个变量放入session

@SessionAttributes(value = "loginSuccessUserInfo")

SpringMVC使用cookie

@RequestMapping("/selectUsers9")
public String selectUsers9(@CookieValue(value="loginUname") String loginUname) {
   //相当于是在cookie中寻找名字为loginUname,并把值赋给对象loginUname
   System.out.println(loginUname);
   return "showUsers";
}

SpringMVC文件上传

引入jar包

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

配置MultipartResolver

 <!--multipartResolver配置 id必须为multipartResolver,需要提前引入p空间注入-->
 <bean id="multipartResolver"
       class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
       p:defaultEncoding="UTF-8"
       p:maxUploadSize="5242880"
       p:uploadTempDir="file:/d:/file/temp"
 />

jsp表单的编写

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <center>
      <!-- 需要设置enctype属性-->
      <form method="post" enctype="multipart/form-data" action="user/upload">
           上传图片:
            <input type="file" name="file" />
            <button>提交</button>
      </form>
  </center>
</body>
</html>

controller 编写

@Controller
@RequestMapping(value = "/upload")
public class UploadController {
    @RequestMapping(value = "/uploadVul")
    public ModelAndView uploadVul(UploadVul uploadVul, HttpServletRequest request, @RequestParam(value = "file") MultipartFile file){
        try {
            //将文件转移到服务器的某个位置
            file.transferTo(new File("D:\\java_second\\projectTest1\\src\\main\\webapp\\uploadFile"+file.getOriginalFilename()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/WEB-INF/upload");
        uploadVul.setDiscover((String) request.getSession().getAttribute("loginSuccessUserInfo"));
        return modelAndView;
    }
}
方法名称方法解释
byte [] getBytes()获取文件数据
String getContentType()获取文件MIMETYPE类型,如image/jpeg,text/plain等
InputStream getInputStream()获取文件输入流
String getName()获取表单中文件组件的名称 name值!
String getOriginalFilename()获取文件上传的原名
long getSize()获取文件的字节大小,单位为byte
boolean isEmpty()是否有长传的文件
void transferTo(File dest)可以将上传的文件保存到指定的文件中

SSM整合

  1. 导入所有框架所需要的jar包
  2. 编写mybatis配置文件:包括映射文件所在的mapper包
  3. 配置Spring框架配置文件:包括service包的扫描
  4. Spring整合mybatis:编写持久层mapper接口,和mapper映射文件放在一起;在Spring映射文件中连接数据库,创建sqlsessionfactory,并扫描映射文件
  5. 编写springMVC配置文件:扫描controller包,配置前缀后缀,创建multipartresolver
  6. 配置web.xml中的前端控制器,以及spring配置文件信息,用于service注入controller
  7. 层次:service中包含mapper接口属性,controller中包含service接口属性

分页控件的使用

  1. 添加jar包
<!-- 添加分页插件的依赖包 -->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.1.2</version>
</dependency>
  1. 在mybatis.xml配置拦截器(拦截SQL语句,加上limit)
<plugins>
   <plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins> 

在configuration标签中是有顺序的

  1. 在service层当中添加分页方法
//分页查询
@Override
public PageInfo<Items> selectItems(int pageindex, int pagesize) {
    //开启分页  在后面调用查询语句的时候会加入limit
    PageHelper.startPage(pageindex,pagesize);
    //调用查询所有的方法  (会被加入limit)
    List<Items> itemsList=  itemsMapper.selectItems();
    //组装pageinfo对象返回
    PageInfo<Items> pageInfo=new PageInfo<Items>(itemsList);
    return pageInfo;
}
  1. controller的使用
@RequestMapping("/selectItemsListByPage")
public ModelAndView selectItemsListByPage(@RequestParam(value ="pageindex",defaultValue ="1" ) int pageindex)
{
    PageInfo<Items> pageInfo = itemsService.selectItems(pageindex,3);
    ModelAndView modelAndView=new ModelAndView();
    modelAndView.addObject("pageInfo",pageInfo);
    modelAndView.setViewName("showItemsByPage");
    return modelAndView;
}
  1. jsp当中进行循环展示
<c:forEach var="items" items="${pageInfo.list}">
    ${items.name}<br/>
</c:forEach>

总共查询到<span>${pageInfo.total}</span>条记录,
共<span>${pageInfo.pages}</span>页
当前是第<span>${pageInfo.pageNum}</span>页

<c:forEach var="i" begin="1" end="${pageInfo.pages}" >
    <a href="selectItemsListByPage?pageindex=${i}">${i}</a>&nbsp;&nbsp;
</c:forEach>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值