文章目录

  • mybatis
    • 开发我的第一个mybatis程序
    • 关于mybatis的核心API:SqlSession对象。
      • mybatis连接数据库操作
    • log4j
    • jackson
    • parameterType 属性用来给sql语句传值的.
    • resultType 指定查询结果集封装的数据类型
    • resultMap字段名 和 属性名 映射
    • mybatis中dao的实现类可以不写,mybatis框架会利用JDK的动态代理机制动态的在内存中生成daoimpl.class字节码:
    • ${} 先进行sql语句的拼接,然后再编译。
    • #{} 先进行sql语句框架的编译,然后再传值。
    • 1. 在类的根路径下,新建一个jdbc.properties文件。配置连接数据库的信息。
    • 2. 编辑mybatis-config.xml:核心配置文件主要配置连接数据库的信息,以及“sql语句配置文件”的路径。
    • 3. 提供一个配置sql语句的配置文件,通常这种文件一般都叫做:sql映射文件(SqlMapper.xml)
    • 动态sql
      • \<sql>代码片段
      • \<include>引用代码片断
      • \<if> 条件判断
      • \<where> 多条件查询
      • \<set>
      • 指定参数位置
      • 入参是map
      • 返回值是 map
      • resultMap结果映射
      • 返回主键自增
      • foeach
      • where--if 分页并模糊
    • 事务
    • 缓存
  • spring
    • spring需要的maven依赖
    • spring的配置文件 applicationContext.xml
    • 主配置文件 total.xml
      • 取出 applicationContext 中创建的对象
    • DI (Dependency Injection)给属性赋值
    • DI 是ioc的技术实现,
    • 简单类型
    • 1.简单类型 set注入
    • 2.引用类型set注入
    • 3.引用类型自动注入
    • 4.构造注入
    • 5.数组和集合类型
    • ioc
    • 改进 spring的配置文件 applicationContext.xml, 使用 anno注解的方式
      • @Component 创建对象的,
        • 创建对象的,等同于\\的功能
    • spring中和@component功能一致,创建对象的注解还有:
      • @Repository(用在持久层类的上面) : 放到dao的实现类上面,
        • 表示创建dao对象,dao对象是能访问数据库的.-
      • @Service(用在业务层类的上面) : 放在service的实现类上面,
        • 创建service对象,service对象是做业务处理,可以有事务等功能的.
      • @Controller(用在控制器的上面) : 放在控制器(处理器)类的上面,创建控制器对象的,
        • 控制器对象,能够接收用户提交的参数,显示请求的处理结果.
        • 以上三个注解的使用语法和@Component一样的,都能创建对象,但是这三个注解还有额外的功能.* @Repository , @Service , @Controller是给项目的对象分层的,
    • aop
      • aop的 applicationContext.xml
        • 动态代理
    • Aop:面向切面编程,
        • 术语
      • aspectj框架的使用。
      • aop使用到的注解
        • @Aspect 作用:表示当前类是切面类
        • @Before 前置通知
        • 指定通知方法中的参数 : JoinPoint
        • @AfterReturning :后置通知
        • @Around : 环绕通知
        • @AfterThrowing : 异常通知
        • @After : 最终通知
        • @Pointcut: 定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,
    • mybatis -- spring 结合使用
      • maven的 pom.xml
      • mybdatis-config.xml
      • applicationContext.xml
      • mybatis-Mapper
      • 使用spring事务管理
    • spring -- web
      • maven中添加依赖
      • 使用 Spring 的监听器 ContextLoaderListener 需要在 web.xml文件中 注册该监听器
      • java代码
  • spring-mvc
    • 第一个spring-mvc项目
      • maven的pom.xml
        • 需要在tomcat服务器启动后,创建DispatcherServlet对象的实例
        • 在 springMVC.xml文件中
    • 注册声明过滤器,解决请求响应乱码问题
    • @RequestMapping 注解
    • 接收请求参数
    • 处理器方法的返回值
      • 返回ModelAndView,既有参数,又有视图
      • 返回String(两种形式)
        • 第一种 : 处理器方法返回String--表示逻辑视图名称,需要配置视图解析器
        • 怎么区分 返回的是 什么 ?
      • 返回void,响应ajax请求
      • 返回一个对象
      • 返回一个List集合
      • 注意 : 将Object数据转为JSON(String,User对象,List集合等等)
      • 需要由消息转换器 HttpMessageConverter 完成。而转 换器的开启,需要由来完成。
    • web.xml中 spring-mvc的核心对象DispatcherServlet的uri-pattern导致的静态资源无法访问
      • 解决方案
    • 方案一 :在 springmvc.xml文件中
    • 方案二 : 在 springmvc.xml文件中
    • 转发和重定向
      • 转发
      • 重定向
    • 异常 @ControllerAdvice @ExceptionHandler
    • 拦截器
  • ssm整合
    • maven的pom.xml文件
    • web.xml
    • jdbc.properties
    • mybatis-config.xml
    • mybatisMapper.xml
    • applicationContext.xml
    • DispatcherServlet.xml
    • java.Controller层
    • java.service接口
    • java.service实现类
    • java.dao层
    • java.bean

mybatis

开发我的第一个mybatis程序

  • maven依赖

    •     <!--mybatis 依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><!--mysql 驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency>
      
  • 编辑mybatis-config.xml:核心配置文件主要配置连接数据库的信息,以及“sql语句配置文件”的路径。

    • <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration><!--配置jdbc.properties文件需要这个操作--><!--引入外部独立的资源文件--><properties resource="jdbc.properties" /><!--mybatis的别名机制,使用与全限定类名--><typeAliases><!-- <typeAlias type="com.bjpowernode.bean.Student" alias="Student"/> --><!--使用package方式,那么该package包下的javabean会自动使用简类名作为别名--><package name="com.bjpowernode.bean"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--一般情况下,连接数据库的信息最好配置到属性文件中,修改方便--><property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><!--这里也可以使用 package--><!--<mapper resource="com/bjpowernode/web/dao/StudentDao.xml"/>--><package name="com.bjpowernode.web.dao"/></mappers>
      </configuration>
      
    • 属性配置文件

      • jdbc.driver=com.mysql.cj.jdbc.Driver
        jdbc.url=jdbc:mysql://localhost:3306/db_wkcto
        jdbc.user=root
        jdbc.password=root
        
  • 提供一个配置sql语句的配置文件,通常这种文件一般都叫做:sql映射文件(SqlMapper.xml)
    在类的根路径下新建一个SqlMapper.xml文件,修改mybatis-config.xml配置,

    • 
      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <!--不知道,先随意写-->
      <mapper namespace="aaa"><!--查询语句,查询所有学生信息--><!--id具有唯一性,代表了这条sql语句,将来这个id是需要"拷贝"到java程序中的--><!--思考:我们程序员需要告诉mybatis框架什么信息,mybatis才能自动创建对象,并且自动将查询结果放到java对象的对应属性上--><!--需要告诉mybatis,最终封装的java对象的类型--><!--需要告诉mybatis,最终查询出的结果赋值到javabean的哪个属性上面,怎么告诉呢?查询结果集的列明要和javabean的属性名对应上,如果不一致 可以使用 as 重命名一下--><select id="getAll" resultType="com.bjpowernode.bean.Student">select id sid,name sname,age sage,birth sbirth from tb_student</select>
      </mapper>
      
  • java代码

    关于mybatis的核心API:SqlSession对象。

    • SqlSession sqlSession = factory.openSession(); 开启事务
      // 执行sql语句1
      // 执行sql语句2
      // ...
      sqlSession.commit();
      // ...
      sqlSession.rollback();
      // ...
      sqlSession.close();
      
    • mybatis连接数据库操作

    • SqlSession sqlSession = null;try {//mybatis有一个配置文件叫做:mybatis-config.xmlString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//事务自动提交机制关闭,等同于conn.setAutoCommit(false);// SqlSession对象 等同看作 Connection对象,专门用来执行sql语句的一个对象//开启事务sqlSession = sqlSessionFactory.openSession();//do work(执行核心业务逻辑)//获取所有学生,返回List集合存储所有学生List<Student> students = sqlSession.selectList("getAll");for (Student student : students) {System.out.println(student.getSid() + ","+ student.getSname() + "," + student.getSage()+ student.getSage() + ","+ student.getSbirth());}//没有出现异常,则事务结束,提交事务sqlSession.commit();} catch (IOException e) {//遇到异常回滚if (sqlSession != null) {sqlSession.rollback();}e.printStackTrace();}finally{//关闭资源if (sqlSession != null){sqlSession.close();}}
      

log4j

  • maven依赖

    • <!-- Log4j2依赖的JAR配置 -->
      <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>2.3</version>
      </dependency>
      <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.3</version>
      </dependency>
  • 配置文件

    • log4j.rootLogger=DEBUG,Console
      log4j.appender.Console=org.apache.log4j.ConsoleAppender
      log4j.appender.Console.layout=org.apache.log4j.PatternLayout
      log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
      log4j.logger.org.apache=INFO
      

jackson

  • maven依赖

    • <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.0</version>
      </dependency>
      <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version>
      </dependency>
      
  • java代码

    • String json = "";
      //把 student 转为 json格式的数据
      if (student != null){ObjectMapper om = new ObjectMapper();try {json = om.writeValueAsString(student);System.out.println("student转换为的json :"+json);} catch (JsonProcessingException e) {e.printStackTrace();}
      }
      

parameterType 属性用来给sql语句传值的.

  • 专门给sql语句传值的。

  • 可以采用:

    • javabean
    • 简单类型
    • Map
  • 测试使用Map给sql语句传值。

    • <!--parameterType是参数类型,专门负责给sql语句传值resultType是查询结果集的类型,只有在select语句中有parameterType="简单类型",则parameterType可以省略resultType="简单类型" 这个不能省略什么是简单类型: 17个.byte short int long float double boolean charByte Short Integer Long Float Double Boolean CharacterString-->
      <!--javabean给占位符传值的时候,程序员需要告诉mybatis javabean的哪个属性传到哪个占位符上mybatis中的占位符不能使用 ? ,必须使用 #{},并且 #{ 这里需要编写javabean的属性名}
      --><insert id="save" parameterType="Map">insert into tbl_student(id,name,birth) values(#{xuehao},#{xingming},#{shengri})
      </insert>注意:使用Map集合给占位符传值的时候,#{这里必须是map集合的key}
    • java代码

      • //insert
        Map<String,String> stuMap= new HashMap<>();
        stuMap.put("xuehao","1111");
        stuMap.put("xingming","lisi");
        stuMap.put("nianling","30");
        stuMap.put("shengri","1990-10-10");
        int count = sqlSession.insert("save", stuMap);
        System.out.println(count);
        
    • 什么时候parameterType会选择使用Map进行传值?

      javabean不够用的时候,我们可以采用Map集合传值。
      什么时候javabean不够用呢?
      一般情况下都是一个表对应一个javabean。两张表两个javabean。
      假设传值的时候,一些值是A表中的,一些值是B表中的,跨表的情况下,
      javabean没有合适的。(总不能因为这一条sql语句,再新增加一个
      javabean吧!)

      mysql> select * from emp;
      +-------+--------+-----------+------+------------+---------+--------+--------+
      | EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM   | DEPTNO |
      +-------+--------+-----------+------+------------+---------+--------+--------+
      |  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 | 2100.00 | 210.00 |   NULL |
      |  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2100.00 | 210.00 |     20 |
      |  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 2400.00 | 240.00 |     30 |
      |  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2400.00 | 240.00 |     30 |
      |  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |   NULL |     10 |
      |  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |   NULL |     10 |
      |  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |   0.00 |     30 |
      |  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |   NULL |     20 |
      |  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |   NULL |     30 |
      |  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |   NULL |     20 |
      |  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |   NULL |     10 |
      +-------+--------+-----------+------+------------+---------+--------+--------+mysql> select * from dept;
      +--------+------------+----------+
      | DEPTNO | DNAME      | LOC      |
      +--------+------------+----------+
      |     10 | ACCOUNTING | NEW YORK |
      |     20 | RESEARCH   | DALLAS   |
      |     30 | SALES      | CHICAGO  |
      |     40 | OPERATIONS | BOSTON   |
      |     50 |            |          |
      +--------+------------+----------+
      

resultType 指定查询结果集封装的数据类型

  • resultType专门用来指定查询结果集封装的数据类型。

  • resultType可以使用:

    • javabean
    • 简单类型
    • Map 关键是:什么时候使用Map呢? javabean不够用的时候。跨表。
  • resultType只有select语句才有。

  • resultType在select当中任何情况下都是不能省略的。

    <select id="getById"  resultType="com.bjpowernode.bean.Student">selectname,age,birth  <!--注意:当列明与javabean属性名不一致时 起别名!!!-->fromtb_studentwhereid = #{affhfajfghj};<!--当一个sql语句的占位符只有一个,那么这个时候#{这里可以随便写}-->
    </select><select id="selectOne" parameterType="Map" resultType="Emp">select* from emp join dept on emp.deptno = dept.deptno where job = #{MANAGER} and dname = #{RESEARCH} <!-- Map的 key部分-->
    </select>

resultMap字段名 和 属性名 映射

  • <!--resultMap:id : 给resultMap指定一个不重复的值type:封装查询结果类型,可以使用别名id标签 : 指定主键的映射property : 封装类的主键属性名称column : 表中主键字段javaType : java中属性类型    可以省略jdbcType : jdbc中字段的类型    可以省略result标签 : 非主键绑定association标签:<association property="customer" javaType="customer"><id property="id" column="cid"></id><result property="name" column="name"></result><result property="age" column="age"></result></association>collection 标签 :<collection property="ordersList" ofType="orders">主键绑定<id property="id" column="oid"></id>非主键绑定<result property="orderNumber" column="orderNumber"></result><result property="orderPrice" column="orderPrice"></result></collection>总结:无论是什么关联关系,如果某方持有另一方的集合,则使用<collection>标签完成映射,如果某方持有另一方的对象,则使用<association>标签完成映射。属性名和字段相同的可以省略不指定resultType 是自动匹配封装resultMap 是手动匹配封装
    -->
    <resultMap id="StudentMap" type="Student2"><id property="sid" column="id" ></id><result property="sname" column="name"></result><result property="sage" column="age"></result>
    </resultMap><!-- resultMap 和 resultType 不能共存-->
    <select id = "queryStudent" resultMap = "StudentMap">select * from t_student
    </select>
    

mybatis中dao的实现类可以不写,mybatis框架会利用JDK的动态代理机制动态的在内存中生成daoimpl.class字节码:

但是,要使用这种机制必须做到以下几个必须:

  • 获取dao实例对象的时候,代码变了:

    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    

    这行代码只要执行,必然会在底层JVM中生成daoimpl的字节码,并且同时调用构造方法创建daoimpl的实例对象。

  • 在SqlMapper.xml文件中必须使用这样固定的namespace:

    <mapper namespace="com.wkcto.crm.dao.StudentDao">
    

    ​ 命名空间namespace必须是dao接口的全限定接口名,带有包名。

  • DAO接口当中的方法名必须和sqlId一致。(拿dao接口的方法名作为sql语句的id)

  • 当dao接口中的方法上参数有多个的时候怎么办,怎么给sql语句传值呢?

    注意:当dao接口上方法的参数是多个的时候,要求参数的数据类型必须属于简单类型的范畴。(17种类型之一)。

    parameterType:
    可以使用javabean
    可以使用Map
    可以使用简单类型
    也可以使用多个参数,但是参数的数据类型必须是简单类型。

    另外需要注意的是:参数的个数多于1个,少于3个,建议使用#{arg0} #{arg1}…的方式,参数过多不建议使用。
    因为方法可能参数多的时候会臃肿。

    mybatis3.4版本之前不能使用#{arg0} #{arg1} #{arg2},必须使用#{0} #{1} #{2}…

    实际开发中要注意团队当中使用的mybatis的版本,3.4版本(包括3.4在内)使用的是:arg0
    低版本使用的是:#{0} #{1}…

${} 先进行sql语句的拼接,然后再编译。

  •     <!--${这里必须是value}除非在dao接口方法参数上使用注解进行标注@param("sort")  ${sort}这里 parameterType是给属性赋值 #{}是给属性赋值用的${}是拼接sql语句,没有赋值,parameterType也不需要了在方法参数那里可以使用 @param 注解设置 ${这里的值},有多个值要拼接的话,不能都是value把-->java代码List<Student> getAll(@Param("sort") String sort);<select id="getAll" resultType="Student">select name,birth from tb_student2 order by birth ${sort};</select>
    

#{} 先进行sql语句框架的编译,然后再传值。

1. 在类的根路径下,新建一个jdbc.properties文件。配置连接数据库的信息。

  • 
    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/db_wkcto
    jdbc.user=root
    jdbc.password=root
    

2. 编辑mybatis-config.xml:核心配置文件主要配置连接数据库的信息,以及“sql语句配置文件”的路径。

  • 
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!--配置jdbc.properties文件需要这个操作--><!--引入外部独立的资源文件--><properties resource="jdbc.properties"/><!--settings : 控制mybatis全局行为--><settings><!--设置mybatis输出日志--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><!--mybatis的别名机制,使用与全限定类名--><!--这样有几十个javabean就得起几十个别名--><typeAliases><typeAlias type="com.bjpowernode.bean.Student" alias="Student"/></typeAliases><!--换这一种写法--><typeAliases><!--使用package方式,那么该package包下的javabean会自动使用简类名作为别名--><package name="com.bjpowernode.bean"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--一般情况下,连接数据库的信息最好配置到属性文件中,修改方便--><property name="driver" value="${jdbc.driver}"/> <!--不是EL表达式,是mybatis中自定义的一种语法格式--><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><!--提供一个配置sql语句的配置文件.一般通常叫做 SqlMapper.xml--><mapper resource="SqlMapper.xml"/></mappers><mappers><!--这里也可以使用 package--><!--<mapper resource="com/bjpowernode/web/dao/StudentDao.xml"/>--><package name="com.bjpowernode.web.dao"/></mappers></configuration>
    

3. 提供一个配置sql语句的配置文件,通常这种文件一般都叫做:sql映射文件(SqlMapper.xml)

  • 
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--在实际开发中,编写sql语句的配置文件一般和dao接口放在一起,并且sql映射文件的文件名要和dao接口的名字一致,只是开发规范,不是必须的-->
    <!--所以,这里要写 dao接口的全限定接口名,可以实现自动创建-->
    <mapper namespace="dao接口的全限定接口名"><!--mybatis中dao的实现类可以不写,mybatis框架会利用JDK的动态代理机制在内存中生daoimpl.class字节码文件但是,要使用这种机制必须做到一下几个必须:1.获取dao实例对象的时候,代码变了:private StudentDao studentDao =                                                     SqlSessionUtil.getCurrentSqlSession().getMapper(StudentDao.class);这行代码只要执行,必然会在底层JVM中生成daoimpl的字节码,并且同时调用构造方法创建daoimpl的实例对象2.在SqlMapper.xml文件中必须使用这样固定的namespace:<mapper namespace="com.bjpowernode.web.dao.StudentDao">命名空间namespace必须是dao接口的全限定类名,带有包名.3.DAO接口当中的方法名必须和sqlId一致,(拿dao接口的方法名作为sqk语句的id)在原先的dao接口实现类中有这样一段代码:SqlSessionUtil.getCurrentSqlSession().insert("save",s);这里是执行sql语句,参数有两个,一个是sql映射的id,一个是参数拿dao接口的方法名作为sql语句的id!!!!!!!!!int save(Student s);id对方法名,参数对参数,<insert id="save" parameterType="Student">
    --><!--       dao接口中的方法名      参数类型--> <insert id="save" parameterType="Student">insert into tb_Student2(id,name ,birth) values(#{id},#{name},#{birth})</insert><!--当dao接口中的方法参数上有多个的时候怎么办,怎么给sql语句传值呢?注意:当dao接口方法的参数的多个的时候,要求参数的数据类型必须属于简单数据类型的范畴(17种类型之          一)才能使用这种方式--><insert id="save2" >insert into tb_Student2(id,name,birth) values(#{arg0},#{arg1},#{arg2})</insert><!--id具有唯一性,代表了这条sql语句,将来这个id是需要"拷贝"到java程序中的--><!--思考:我们程序员需要告诉mybatis框架什么信息,mybatis才能自动创建对象,并且自动将查询结果放到java对象的对应属性上--><!--需要告诉mybatis,最终封装的java对象的类型--><!--需要告诉mybatis,最终查询出的结果赋值到javabean的哪个属性上面,怎么告诉呢?查询结果集的列明要和javabean的属性名对应上,如果不一致 可以使用 as 重命名一下--><select id="getAll" resultType="com.bjpowernode.bean.Student">select id sid,name sname,age sage,birth sbirth from tb_student</select><!-- parameterType在进行传值的时候,可以采用 :javabean.简单类型.Map....什么时候会选择使用Map集合进行传值呢?javabean不够用的时候,一般情况下,一个表对应一个javabean.假设传值的时候,一些值是A表中的,一些值的B表中的,跨表的情况下,javabean没有合适的.--><!--<insert id="save" parameterType="java.util.Map" > </insert><insert id="save" parameterType="java.util.HashMap" > </insert><insert id="save" parameterType="Map" > </insert><insert id="save" parameterType="map" > </insert>都可以写,都支持--><!--insert into tb_student values(#{xuehao},#{xingming},#{nianling},#{shengri});这样也可以--><insert id="save" parameterType="Map"><!--这里是Map集合的key部分-->insert into tb_student(id,name,age,birth) values(#{xuehao},#{xingming},#{nianling},#{shengri});</insert><!--resultType可以使用:javabean.简单类型.Map....resultType只有select语句才有resultType在select当中任何情况下都不能省略resultType什么时候使用Mapjavabean不够用的时候,跨表--><select id="getEnames" resultType="String">select ename from emp;</select><select id="getByName"  resultType="Map">selecte.ename,e.sal,d.dnamefromemp ejoindept done.deptno = d.deptnowheree.ename = #{ename};</select></mapper>
    

动态sql

<sql>代码片段

  • <sql id="columns"> id,username,birthday,sex,address</sql>
    

<include>引用代码片断

  • select
    <include refid="columns"></include>
    from users
    where username like '%${userName}%'
    

<if> 条件判断

  • <if test="userName != null ">and username like '%${userName}%'
    </if>注意:test 这里使用的是类中的成员变量名称
    

<where> 多条件查询

  • <select id="getByCondition" resultType="users" parameterType="users">select <include refid="columns"></include>from users<where><if test="address != null">and address like '%${address}%'</if></where>
    </select>

<set>

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

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

指定参数位置

  • 如果参数不是实体类成员变量,是散的条件,可以使用指定下标位置的方式进行传参 接口中:

  • <!--另外需要注意的是:参数的个数多于1个,少于3个,建议使用#{arg0} #{arg1}...的方式,参数过多不建议使用。
    因为方法可能参数多的时候会臃肿。mybatis3.4版本之前不能使用#{arg0} #{arg1} #{arg2},必须使用#{0} #{1} #{2}...实际开发中要注意团队当中使用的mybatis的版本,3.4版本(包括3.4在内)使用的是:arg0
    低版本使用的是:#{0} #{1}....
    -->
    java代码
    List<Users> getByLocat ion(Date begin, Date end);
    xml中:
    <select id="getByLocat ion" resultType="users">
    select <include refid="columns"></include>
    from users
    where birthday between #{arg0} and #{arg1}
    </select>

入参是map

  • 也是因为传入的条件实体类无法封装,使用map封装各种条件,使用键值对的方式来传参。 接口中:

  • java代码
    String job = "MANAGER";
    String dname = "RESEARCH";
    Map<String,String> map = new HashMap<>();map.put("MANAGER",job);map.put("RESEARCH",dname);Emp emp = sqlSession.selectOne("selectOne", map);System.out.println(emp);<select id="selectOne" parameterType="Map" resultType="Emp">select* from emp join dept on emp.deptno = dept.deptno where job = #{MANAGER} and dname = #{RESEARCH} <!-- Map的 key部分-->
    </select>
    

返回值是 map

  • 
    java 代码
    List<Map<String, Object>> listMap = sqlSession.selectList("getByJob", "MANAGER");
    listMap.forEach(System.out::println);<select id="getByName"  resultType="Map">selecte.ename,e.sal,d.dnamefromemp ejoindept done.deptno = d.deptnowheree.ename = #{ename};
    </select>
    

resultMap结果映射

  • <!--resultMap:id : 给resultMap指定一个不重复的值type:封装查询结果类型,可以使用别名id标签 : 指定主键的映射property : 封装类的主键属性名称column : 表中主键字段javaType : java中属性类型    可以省略jdbcType : jdbc中字段的类型    可以省略属性名和字段相同的可以省略不指定resultType 是自动匹配封装resultMap 是手动匹配封装
    -->
    <resultMap id="StudentMap" type="Student2"><id property="sid" column="id" ></id><result property="sname" column="name"></result><result property="sage" column="age"></result>
    </resultMap><!-- resultMap 和 resultType 不能共存-->
    <select id = "queryStudent" resultMap = "StudentMap">select * from t_student
    </select>
    

返回主键自增

  • 
    <!--keyProperty : Student对象的哪个属性来接收这个返回的主键值resultType : 返回主键类型order : 在插入语句前还是后AFTER:先插入再返回主键BEFORE: 先生成再完成插入-->
    <insert id="insertStudent" parameterType="Student"><selectKey keyProperty="id" resultType="int" order="AFTER">select last_insert_id()</selectKey><!--  先生成随机字符串,再返回  这里用的是 mysql的方法 --><selectKey order="BEFORE" keyProperty="id" resultType="string">select uuid()</selectKey>insert into student(name,age) values(#{name},#{age})
    </insert>
    

foeach


<!--collection:接收传入的内容,如果是List集合,则值为list ,如果是数组,则值为array,如果是
Map, 则值为map.item : 遍历出来的临时变量或对象.separator: 多个值之间的分隔符.open : 整个循环最外层的前括号.close : 整个循环最外层的后括号.
--><!--   foreach array   -->
<!-- 批量删除 -->
<delete id="deleteByIds" >delete from tb_student2 where id in<foreach collection="array" open="(" close=")" separator="," item="id">#{id}</foreach>
</delete><delete id="deleteByIds" >delete from tb_student2 where id in(<foreach collection="array" separator="," item="id">#{id}</foreach>)
</delete><!--  foreach list    -->
<!-- 批量新增 -->
<insert id="saves" parameterType="Student">insert into tb_student2(id,name ,birth) values<foreach collection="list" separator="," item="student">(#{student.id},#{student.name},#{student.birth})</foreach>
</insert><!-- 批量更新 -->
<update id="updateById"><foreach collection="list" separator = ";" item = "student">update student age = #{student.age} where id = #{student.id}</foreach>
</update>
注意:要使用批量更新,必须在jdbc.properties属性文件中的url中添加&allowMultiQueries=true,允许多行操作。

where–if 分页并模糊

  • <!-- 分页查询    -->分页查询java代码应该怎么实现?(pageNo - 1) * pageSize , pageSize分析1:浏览器向服务器提交什么数据?查询条件(有可能是多个条件,也有可能没有条件)pageNo  页码pageSize 每页显示记录条数分析2:服务器向浏览器响应什么数据?浏览器页面上需要展示什么数据?需要返回一:符合查询条件的“当前页”数据。需要返回二:符合查询条件的“总记录”条数。这是一个怎样的json?{"total" : 50 , "dataList" : [{"id":"","name":"","birth":""},             {"id":"","name":"","birth":""}....]}<!--通过 pageNo,pageSize,查询条件,返回当前页的数据--><!--MyBatis中的sql语句不支持数学运算,提前先算好--><!--下面 where -if 语句中,都写上 and , 如果条件不成立,MyBatis会自动把 and 干掉,两个条件都成立,也会自动加 and-->
    <select id="getDataListByCondition" parameterType="Map" resultType="Student">selects.*fromtb_student2 s<where><!--下面  '%' #{name1}(中间必须有空格) '%'MyBatis中的占位符#{}两边必须要有空格,不然MyBatis不会识别这里有一个占位符--><if test="name1 != null and name != ''">and s.name like '%' #{name1} '%'</if><if test="birth1 != null and birth1 != ''">and s.birth = #{birth1}</if></where>order bybirth desclimit#{startIndex} , #{pageSize1}</select>
    
  • 基于 PageHelper 分页:1.maven 坐标<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version></dependency>2.在mybatis-config.xml中加入 plugin 配置在<environments>之前加入<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor" /></plugins><!--查询语句之前调用 PageHelper.startPage 静态方法。
    除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。
    在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个
    方法后的第一个 MyBatis 查询方法会被进行分页。-->3. PageHelper 对象@Testpublic void testSelect() throws IOException {//获取第 1 页,3 条内容PageHelper.startPage(1,3);List<Student> studentList = studentDao.selectStudents();studentList.forEach( stu -> System.out.println(stu));}
    

事务

  • 1.MyBatis使用的事务处理模式是JDBC,是手工提交事务的方式。当我们得到session的时候,默认就是手工提交。但可以做更改。
    session = factory.openSession(true);//true:代理自动提交 false:表示手动提交,默认false
  • 2.MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED,MANAGED是容器管理的事务处理模式

缓存

  • .目的:缓存最终的目的是提高查询效率.

  • 缓存执行的机制:发出数据库的访问请求时,先去缓存查一下,如果有,则直接返回不访问数据库,如果没有则进行数据库访问,查到数据后,在缓存放一 份,再返回客户端。等下一次查询时,重复刚刚的步骤。当数据库中的数据发生变化时,则清空缓存。

  • 一级缓存,一级缓存使用的是SqlSession的作用域,同一个sqlSession共享一级缓存的数据.

自动开启,如果数据库中发生增删改操作后,缓存清空。SqlSession关闭后,清空缓存。

  • 二级缓存,二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的同一个mapper.xml文件,则共享二级缓存作用域.

手工开启,如果数据库中发生增删改操作后,缓存清空。

  • 二级缓顾存开启的步骤
    1).在SqlMapConfig.xml文件中添加开启二级缓存配置
    <setting name="cacheEnabled" value="true"/>
    2).在相应的mapper.xml文件中添加
    <cache /> : 表示这个接口下所有的查询操作都会被保存到二级缓存中
    3).实体类添加java.io.Serializable接口
    

spring

spring需要的maven依赖

  •     <!--spring-context:是ioc功能的,创建对象的。--><!--在你加入spring-context的同时, 间接加入spring-aop的依赖。使用注解必须使用spring-aop依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.22</version><scope>compile</scope></dependency>
    

spring的配置文件 applicationContext.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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--spring的配置文件1.beans:根标签,spring把java对象称为bean2.spring-beans.xsd 是约束文件,和mybatis指定 dtd是一样的.--><!--告诉spring创建对象声明bean,就是告诉spring要创建某个类的对象id : 对象的自定义名称,唯一值.spring通过这个名称找到对象class : 类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)spring就完成了 SomeService someService = new SomeServiceImpl();spring是把创建好的对象放到map中,spring框架有一个map存放对象的.springMap.put(id的值,对象);例如: springMap("someService",new SomeServiceImpl())一个bean标签声明一个对象--><bean id="someService" class="com.bjpowernode.service.impl.SomeServiceImpl"></bean><bean id="someService1" class="com.bjpowernode.service.impl.SomeServiceImpl"></bean><!--spring能创建一个非自定义类对象吗?创建一个存在的某个类的对象--><bean id="myDate" class="java.util.Date"></bean><bean id="sdf" class="java.text.SimpleDateFormat"></bean>
    </beans>
    
  • 主配置文件 total.xml

    • <!--
      包含关系的配置文件:
      spring-total表示主配置文件 : 包含其他配置文件
      主配置文件一般不定义对象的语法:<import resource="其他配置文件路径" />关键字: "classpath" : 表示类路径(class文件所在的目录),在spring的配置文件中要指定其他文件的位置,需要使用classpath,告诉spring到哪里去加载读取文件.
      -->
      <!--加载的是文件列表-->
      <import resource="classpath:ba06/spring-student.xml"></import>
      <!--包含关系的配置文件中可以使用通配符(* : 表示任意字符)注意: 主配置文件名称不能包含在通配符的范围内(不能叫做spring-total.xml)
      -->
      <import resource="classpath:ba06/spring-*.xml"></import>
      
  • 取出 applicationContext 中创建的对象

    • //使用spring容器创建对象// 1.指定spring配置文件的名称String config = "beans.xml";// 2.创建表示sprig容器的对象, ApplicationContext// ClassPathXmlApplicationContext: 表示从类路径中加载spring的配置文件ApplicationContext ac = new ClassPathXmlApplicationContext(config);//从容器中获取某个对象,getBean("配置文件中的bean的id值");SomeService someService = (SomeService) ac.getBean("someService");//使用spring创建好的对象someService.doSome();
      

DI (Dependency Injection)给属性赋值

  • DI 是ioc的技术实现,

  • 简单类型

    • 1.简单类型 set注入

      •     <!--声明Student对象di:给属性赋值//注入 就是 赋值的意思
        简单类型 : spring中规定了java的基本数据类型(包装类也是)和String都是简单类型1.set注入(设置注入) : spring调用类的set方法,你可以在set方法中完成属性赋值操作1.简单类型的set注入<bean id="xxx" class="yyy"><property name="属性名称" value="此属性值"></property>一个property只能给一个属性赋值<property...></property></bean>--><bean id="myStudent" class="com.bjpowernode.ba01.Student"><property name="name" value="张三"></property><!--setName("张三")--><property name="age" value="20"></property><!--setAge(20)--><property name="email" value="zhangsan@123.com"></property></bean><bean id="myDate" class="java.util.Date"><property name="time" value="22217529851752"></property><!--setTime(22217529851752)--></bean>
        
    • 2.引用类型set注入

      • <!--2.引用类型的set注入--><!--<bean id="xxx" class="yyy"><property name="属性名称" ref="bean的id(在spring中不就是对象的名称么))"></property>一个property只能给一个属性赋值<property...></property></bean>--><bean id="myStudent" class="com.bjpowernode.ba02.Student"><property name="name" value="张三"></property><!--setName("张三")--><property name="age" value="20"></property><!--setAge(20)--><property name="school" ref="myShcool"></property><!--setSchool(mySchool)--></bean><bean id="myShcool" class="com.bjpowernode.ba02.School"><property name="name" value="动力节点"></property><property name="address" value="郑州"></property></bean>
        
    • 3.引用类型自动注入

      • 
        <!--引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值,不用你在给引用类型赋值了使用的规则常用的是 byName, byType
        1. byName(按名称注入) : java类中引用类型的属性名和spring容器中(配置文件)<bean>的id一致且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型语法规则:<bean id="xxx" class="yyy" autowire="byName">//简单类型赋值<property>...</bean>2 byType(按类型注入) : java类中引用的数据类型和spring容器中的(配置文件)<bean>的class属性是同源关系,这样的bean能够赋值给引用类型同源就是一类的意思:1.java类中引用类型的数据类型和bean的class的值是一样的.2.java类中引用类型的数据类型和bean的class的值是父子类关系的.3.java类中引用类型的数据类型和bean的class的值是接口和实现关系的.语法规则:<bean id="xxx" class="yyy" autowire="byType">//简单类型赋值<property>...</bean>注意:在byType中,在xml配置文件中声明bean只能有一个符合条件的bean,多于一个是错误的--><!--使用byName进行赋值--><bean id="student" class="com.bjpowernode.ba04.Student" autowire="byName"><property name="name" value="张三" ></property><property name="age" value="20" ></property></bean><bean id="school" class="com.bjpowernode.ba04.School"><property name="name" value="清华大学"></property><property name="address" value="北京"></property></bean>
    • 4.构造注入

      • <!--构造注入 : Spring调用类的有参构造方法,在创建对象的同时,在构造方法中给属性赋值.构造注入使用<constructor-arg>标签<constructor-arg>标签::一个<constructor-arg>表示构造方法一个参数<constructor-arg>标签属性name:表示构造方法的形参名index:表示构造方法的参数的位置,参数从左往右位置是 0,1,2..的顺序value:构造方法的形参类型是简单类型的,使用valueref:构造方法的形参类型是引用类型的,使用ref
        --><!--使用name属性实现构造注入--><!--下面先创建了student对象,赋值学校的时候学校还没有呢,不管spring很智能,他会进行二次扫描赋值--><bean id="myStudent1" class="com.bjpowernode.ba03.Student"><constructor-arg name="school" ref="myShcool" ></constructor-arg><constructor-arg name="name" value="张三" ></constructor-arg><constructor-arg name="age" value="20" ></constructor-arg></bean><!-- 顺序无所谓,但是,按照顺序写可以省略index--><bean id="myStudent2" class="com.bjpowernode.ba03.Student"><constructor-arg index="2" ref="myShcool" ></constructor-arg><constructor-arg index="0" value="李四" ></constructor-arg><constructor-arg index="1" value="22" ></constructor-arg></bean><bean id="myStudent3" class="com.bjpowernode.ba03.Student"><constructor-arg value="王五" ></constructor-arg><constructor-arg value="28" ></constructor-arg><constructor-arg ref="myShcool" ></constructor-arg></bean><bean id="myShcool" class="com.bjpowernode.ba03.School"><property name="name" value="动力节点"></property><property name="address" value="北京"></property></bean><!--创建File,使用构造注入--><bean id="myFile" class="java.io.File"><constructor-arg name="parent" value="D:\Java\spring\spring-course\ch02-di-xml\src\main\java\com\bjpowernode\ba03\Student.java"></constructor-arg><constructor-arg name="child" value="Student.java"></constructor-arg></bean>
        
    • 5.数组和集合类型

      • <bean id="myShcool" class="com.bjpowernode.ba03.School"><property name="name" value="动力节点"></property><property name="address" value="北京"></property><property name='属性名'><!--什么类型就用什么标签--><list><value>参数</value><value>参数</value><value>参数</value></list></property><!-- Array --><property name='属性名'><!--什么类型就用什么标签--><array><value>参数</value><value>参数</value><value>参数</value></array></property><!-- map --><property name='属性名'><!--什么类型就用什么标签--><map><!-- key : key值value : value值--><entry key='' value='' /><entry key='' value='' /><entry key='' value='' /></map></property><!-- properties --><property name='属性名'><!--什么类型就用什么标签--><props><!-- key : key值value : value值,放在标签对之间--><prop key ='driver'>com.mysql/cj/jdbc.Driver</prop><prop key =''>value</prop><prop key =''>value</prop></props></property></bean>

ioc

  • IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。
    描述的:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。控制: 创建对象,对象的属性赋值,对象之间的关系管理。反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,给属性赋值。正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。public static void main(String args[]){Student student = new Student(); // 在代码中, 创建对象。--正转。}容器:是一个服务器软件, 一个框架(spring)为什么要使用 ioc : 目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。
    

改进 spring的配置文件 applicationContext.xml, 使用 anno注解的方式

  • <?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"><!--声明组件扫描器(component-scan),组件就是java对象base-package:指定注解在你的项目中的包名.component-scan工作方式:spring会扫描遍历base-package指定的包,把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值加入了component-scan标签,配置文件的变化:1.加入了一个新的约束文件spring-context.xsd2.给这个新的约束文件起个命名空间的名称--><context:component-scan base-package="com.bjpowernode.ba07" /><!--指定多个包的三种方式-->
    <!--第一种方式:使用多次组件扫描器,指定不同的包--><context:component-scan base-package="com.bjpowernode.ba01" /><context:component-scan base-package="com.bjpowernode.ba02" /><!--第二种方式:使用分隔符( ; 或 , )分阁多个包--><context:component-scan base-package="com.bjpowernode.ba01;com.bjpowernode.ba02" /><!--第三种方式:指定父包--><!--不要指定太过了,不然扫描慢了--><context:component-scan base-package="com.bjpowernode" /><!--使用注解 + 配置文件--><context:component-scan base-package="com.bjpowernode.ba08" /><!--加载属性配置文件--><context:property-placeholder location="test.properties" file-encoding="UTF-8" />java赋值代码@Value("${name}")private String name;
    </beans>
    

@Component 创建对象的,

  • 创建对象的,等同于<bean></bean>的功能
  • <!-- @Component属性: value 就是对象的名称,也就是bean的id值           value的值是唯一的,创建的对象在整个spring容器中就一个      位置:在类上面
    -->
    @component(value = "myStudent")等同于
    <bean id="myStudent" class="com.bjpowernode.ba01.Student"></bean>//省略value
    @Component("myStudent")//这个常用
    //不指定对象名称,由spring提供默认名称:
    @component
    public class Student{/*** @Value: 简单类型的属性赋值*      属性: value 是String类型的,表示简单类型的属性值*      位置 : 1.在属性定义的上面,无需set方法,推荐使用*            2.在set方法上面使用*/@Value("李四")private String name;/**  1* 引用类型* @AutoWired : spring框架提供的注解,实现引用类型的赋值* spring中通过注解给引用类型赋值,使用的是自动注入原理,支持 byName, byType* @AutoWired: 默认使用的是 byType自动注入**      位置: 1.在属性定义上面使用,无需set方法,推荐使用*           2.在set方法上面使用**      如果要使用byName方式,需要做的是:*          1.在属性上面加入@AutoWired*          2.在属性上面加入@Qualifier(value="bean的id") : 表示使用指定名称的bean完成赋值**///byType自动注入@Autowiredprivate School school;//byName自动注入@Autowired()//指定name@Qualifier(value="mySchool")   //顺序没要求,private School school;/** 2* 引用类型* @Resource : 来自JDK中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值*              使用的也是自动注入原理,支持byName,byType,默认是byName**      位置 : 1.在属性定义的上面,无需set方法,推荐使用.*            2.在set方法的上面**        @Resource :只使用byName方式,需要增加一个属性 name*      name 的值是bean 的 id值*///默认是byName, 先使用byName自动注入,如果byName失败了,再使用byType@Resourceprivate School school;@Resource(name="mySchool")private School school;
    }
    
  • spring中和@component功能一致,创建对象的注解还有:

@Repository(用在持久层类的上面) : 放到dao的实现类上面,

  • 表示创建dao对象,dao对象是能访问数据库的.-

@Service(用在业务层类的上面) : 放在service的实现类上面,

  • 创建service对象,service对象是做业务处理,可以有事务等功能的.

@Controller(用在控制器的上面) : 放在控制器(处理器)类的上面,创建控制器对象的,

aop

aop的 applicationContext.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: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 https://www.springframework.org/schema/aop/spring-aop.xsd"><!--对象声明使用注解方式了--><context:component-scan base-package="com.bjpowernode.ba08"/><!--把对象交给spring容器,由spring容器统一创建,管理对象--><!--声明目标对象--><!--<bean id="someService" class="com.bjpowernode.ba01.SomeServiceImpl"></bean>--><!--声明切面类对象--><!--<bean id="myAspect" class="com.bjpowernode.ba01.MyAspect"></bean>--><!--声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象.创建代理对象是在内存中实现的,修改目标对象的内存中的结构.创建为代理对象,所以目标对象就是被修改后的代理对象aspectj-autoProxy:会把spring容器中的所有的目标对象,一次性都生成代理对象.--><!--<aop:aspectj-autoproxy/>--><!--如果你期望目标类有接口,使用CGLib代理proxy-target-class="true" : 告诉框架,要使用CGLib动态代理--><aop:aspectj-autoproxy proxy-target-class="true" />
</beans>
  • 动态代理
    • 实现方式:

    • jdk动态代理:  使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。jdk动态代理要求目标类必须实现接口cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的
      
    • 动态代理的作用:

      • 1)在目标类源代码不改变的情况下,增加功能。
        2)减少代码的重复
        3)专注业务逻辑代码
        4)解耦合,让你的业务功能和日志,事务非业务功能分离。
        
  • Aop:面向切面编程,

    •  基于动态代理的,可以使用jdk,cglib两种代理方式。Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了, 让开发人员用一种统一的方式,使用动态代理。
      
    • AOP(Aspect Orient Programming)面向切面编程Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。切面的特点: 一般都是非业务方法,独立使用的。Orient:面向, 对着。Programming:编程oop: 面向对象编程怎么理解面向切面编程 ? 1)需要在分析项目功能时,找出切面。2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能
      
  • 术语
    • 1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象5)Advice:通知,通知表示切面功能执行的时间。说一个切面有三个关键的要素:1)切面的功能代码,切面干什么2)切面的执行位置,使用Pointcut表示切面执行的位置3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。
      
  • aspectj框架的使用。

    • 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。

    • aspectJ框架实现aop有两种方式:

      • 使用xml的配置文件 : 配置全局事务
      • 使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。
    • 切面的执行时间,

      • 这个执行时间在规范中叫做Advice(通知,增强)在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签1)@Before2)@AfterReturning3)@Around4)@AfterThrowing5)@After
        
    • 表示切面执行的位置,使用的是切入点表达式。

      • com.service.impl
        com.bjpowrnode.service.impl
        cn.crm.bjpowernode.serviceexecution(* *..service.*.*(..))
        execution(访问权限 方法返回值 方法声明(参数) 异常类型)√            √
        

aop使用到的注解

@Aspect 作用:表示当前类是切面类

  • /*** @Aspect : 是aspectj框架中的注解.*      作用:表示当前类是切面类*      切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码*      位置:在类定义的上面@Order() : 表示执行顺序,数值越小,越先执行*/@Component
    @Aspect
    @Order(1)
    public class MyAspect {}
    

@Before 前置通知

  •     /***  定义方法:方法是实现切面功能的.*  方法的定义要求:*      1.公共的方法 public*      2.方法没有返回值*      3.方法名自定义*      4.方法可以有参数,也可以没有参数.*          如果有参数,参数不是自定义的,有几个参数类型可以使用.*//*** @Before : 前置通知*  属性:value, 是切入点表达式,表示切面的功能执行的位置*  位置:在方法的上面*  特点:*      1.在目标方法之前执行的*      2.不会改变目标方法的执行结果*      3.不会影响目标方法的执行*/@Component
    @Aspect
    public class MyAspect {@Before(value = "execution(public void                                                        com.bjpowernode.ba01.SomeServiceImpl.doSome(String,Integer))")public void myBefore(){//就是你切面要执行的功能代码System.out.println("前置通知 , 切面功能:在目标方法之前输出执行时间:"+new Date());}}
    

指定通知方法中的参数 : JoinPoint

  •     /*** 指定通知方法中的参数 : JoinPoint* JoinPoint : 业务方法,要加入切面功能的业务方法*      作用是:可以在通知方法中获取方法执行时的信息, 例如方法名称,方法实参*      如果你的切面功能中需要用到方法的信息,就加入 JoinPoint.*      这个 JoinPoint 参数的值是由框架赋予,必须是第一个位置的参数*/@Before(value = "execution(* *..SomeServiceImpl.do*(..))")public void myBefore(JoinPoint jp){//获取方法的完整定义System.out.println("方法的签名(定义) = " + jp.getSignature());System.out.println("方法的名称 = " + jp.getSignature().getName());//获取方法的实参Object[] args = jp.getArgs();for (Object arg : args) {System.out.println("方法的参数:"+arg);}System.out.println("3--前置通知 , 切面功能:在目标方法之前输出执行时间 : " + new Date());}
    

@AfterReturning :后置通知

  •     /***  后置通知定义方法:方法是实现切面功能的.*  方法的定义要求:*      1.公共的方法 public*      2.方法没有返回值*      3.方法名自定义*      4.方法有参数,推荐使用Object ,参数名自定义*//*** @AfterReturning:后置通知*      属性: 1.value 切入点表达式*           2.returning 自定义的变量,表示目标方法的返回值*              自定义变量名必须和通知方法的形参名一样.*     位置:在方法定义的上面** 特点:*      1.在目标方法之后执行的.*      2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能*          Object res = doOther();*      3.可以修改这个返回值**      后置通知的执行*          Object res = doOther();*          参数传递 : 传值 , 传引用*          myAfterReturning(res);*          System.out.println("res="+res)*/@AfterReturning( value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")public void myAfterReturning(Object res){System.out.println("后置通知 : 在目标方法之后执行,获取的返回值是:" + res);if ("abc".equals(res)){//做一些功能}else{//做其他功能}//修改目标方法的返回值,会否会影响最后方法的调用结果if (res != null){res = "hhh";}}@AfterReturning( value = "execution(* *..SomeServiceImpl.doStudent(..))",returning = "res")public void myAfterReturning2(JoinPoint jp,Object res){System.out.println("后置通知,方法发定义:" + jp.getSignature());System.out.println("后置通知 : 在目标方法之后执行,获取的返回值是:" + res);if (res != null){Student student = (Student) res;student.setName("zs");student.setAge(10);}}
    

@Around : 环绕通知

  •     /***  环绕通知定义方法:方法是实现切面功能的.*  方法的定义要求:*      1.公共的方法 public*      2.方法必须有一个返回值,推荐使用Object*      3.方法名自定义*      4.方法有参数,固定参数ProceedingJoinPoint
    e    *//***  @Around : 环绕通知*      属性:value 切入点表达式*      位置:在方法定义的上面**  特点:*      1.它是功能最强的通知*      2.在目标方法发前和后都能增强功能*      3.控制目标方法是否被调用执行*      4.修改原来的目标方法的执行结果,影响最后的调用结果**  环绕通知,等同于JDK动态代理,InvocationHandler接口**      参数: ProceedingJoinPoint 就等同于 Method*          作用: 执行目标方法**  返回值 : 目标方法的执行结果,可以被修改**  环绕通知 : 经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务*/@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")public Object myAround(ProceedingJoinPoint pjp) throws Throwable {//实现环绕通知String name = "";Object[] args = pjp.getArgs();if(args != null && args.length > 1){Object arg = args[0];name = (String) arg;}System.out.println("环绕通知 : 在目标方法之前,输出时间:"+ new Date());Object result = null;//1.目标方法的调用if ("zhangsan".equals(name)){result = pjp.proceed(); // method.invoke();  Object result = doFirst();}//2.在目标方法发前或后加入功能System.out.println("环绕通知 : 在目标方法之后,提交事务");if (result != null){result = "Hello Aspectj AOP";}//返回目标方法发执行结果return result;}
    

@AfterThrowing : 异常通知

  •     /***  异常通知定义方法:方法是实现切面功能的.*  方法的定义要求:*      1.公共的方法 public*      2.方法没有返回值*      3.方法名自定义*      4.方法有一个参数 Exception, 如果还有就是 JoinPoint,*//*** @AfterThrowing : 异常通知*      属性 1. value 切入点表达式*          2. throwing 自定义的变量,表示目标方法抛出的异常对象*              变量名必须和方法参数名一样**  特点:*      1.在目标方法抛出异常时执行的*      2.可以做异常的监控程序,监控目标方法执行时是不是有异常.*          如果有异常,可以发送邮件,短信进行通知**  执行就是:*      try{*          SomeServiceImpl.doSecond();*      }catch(Exception e){*          myAfterThrowing(e);*      }*/@AfterThrowing(value = "execution(**..SomeServiceImpl.doSecond(..))",throwing="e")public void myAfterThrowing(Exception e){System.out.println("异常通知 : 方法发送异常时,执行 : " + e.getMessage());}

@After : 最终通知

  •     /***  最终通知定义方法:方法是实现切面功能的.*  方法的定义要求:*      1.公共的方法 public*      2.方法没有返回值*      3.方法名自定义*      4.方法没有参数, 如果有就是 JoinPoint,*//*** @After : 最终通知*      属性: value 切入点表达式*      位置:方法的上面**  特点:*      1.总是会执行(异常也会执行)*      2.在目标方法之后执行的**  try{*     SomeServiceImpl.doThird(..)*  }catch(Exception e){**  }finally{*      myAfter()*  }*/@After(value = "execution(* *..SomeServiceImpl.doThird(..))")public void myAfter(){System.out.println("执行最终通知,总是被执行的代码");//一般做资源清除工作的.}
    

@Pointcut: 定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,

  •     @After(value = "mypt()")public void myAfter(){System.out.println("执行最终通知,总是被执行的代码");//一般做资源清除工作的.}@Before(value = "mypt()")public void myBefore(){System.out.println("前置通知,在目标方法执行之前执行");}/*** @Pointcut: 定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,*              可以使用 @Pointcut 进行复用*      属性: value 切入点表达式*      位置: 方法的定义上面**  特点:*      当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名了.*      其他的通知中,value属性就可以使用这个方法名称(带括号),代替切入点表达式了.*/@Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))")private void mypt(){//无需代码}
    

mybatis – spring 结合使用

maven的 pom.xml

  • <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bjpowernode</groupId><artifactId>ch07-spring-mybatis</artifactId><version>1.0</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!--spring 依赖 ioc--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.22</version></dependency><!--spring 事务用到的--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.22</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.22</version></dependency><!--mybatis 依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><!--mybatis 和 spring集成的依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency><!--mysql 驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!--阿里公司的数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency></dependencies><build><!--目的是把src/main/java目录中的xml文件包含到输出结果中.输出到classes目录中--><resources><resource><directory>src/main/java</directory><!--所在的目录--><includes><!--包括目录下的.properties,.xml 文件都会扫描到--><include>**/*.properties</include><include>**/*.xml</include></includes><!--filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 --><filtering>false</filtering></resource></resources></build>
    </project>
    

mybdatis-config.xml

  • <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--settings : 控制mybatis全局行为--><settings><!--设置mybatis输出日志--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><!--起别名--><typeAliases><package name="com.bjpowernode.bean"/></typeAliases><!--sql mapper(sql映射文件)的位置--><mappers><!-- name 是包名,这个包中的所有mapper.xml文件一次都能加载--><package name="com.bjpowernode.dao"/></mappers></configuration>
    

applicationContext.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"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"><!--把数据库的配置信息,写在一个独立的文件,编译修改数据库的配置内容要让spring知道jdbc.properties文件的位置啊--><context:property-placeholder location="classpath:jdbc.properties"/><!--声明数据源DataSource,作用是连接数据库的--><bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close"><!--set 注入给DruidDataSource提供连接数据库的信息--><!--使用属性配置文件中的数据, 语法 ${}--><property name="url" value="${jdbc.url}" /><!--setUrl()--><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /><property name="maxActive" value="${jdbc.max}" /></bean><!--声明的是mybatis中提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory的--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!--set注入,把数据库连接池赋给了dataSource属性--><property name="dataSource" ref="myDataSource" /><!--mybatis主配置文件的位置configLocation属性是 Resource 类型,读取配置文件它的赋值,使用value,指定文件路径,使用classPath:表示文件的位置--><property name="configLocation" value="classpath:mybatis-config.xml" /></bean><!--创建dao对象,使用SqlSession的getMapper(Student.class)MapperScannerConfigurer : 在内部调用getMapper()生成每个dao接口的代理对象.--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--指定SqlSessionFactory对象的id--><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /><!--指定包名,包名是dao接口所在的包名.MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper()方法,得到每个接口的dao对象.创建好的dao对象放到spring的容器中.dao对象的默认名称是 接口名首字母小写--><property name="basePackage" value="com.bjpowernode.dao"/></bean><!--声明service  或者   注解 @Service所在的包的位置--> <bean id="studentService" class="com.bjpowernode.service.impl.StudentServiceImpl"><property name="studentDao" ref="studentDao"/></bean><!--声明 service  --><context:component-scan base-package="com.bjpowernode.service" /><!--使用spring事务管理 注解方式还有一种是 配置文件的方式 在下面--><!--1.声明事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--指定数据源(连接的数据库)--><property name="dataSource" ref="myDataSource" /></bean><!--2.开启事务注解驱动,告诉spring我们要使用注解管理事务,创建代理对象transaction-manager:表示事务管理器的对象id!!!!!!!!尾部是 tx的 不要选错了xmlns:tx="http://www.alibaba.com/schema/stat"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:tx="http://www.springframework.org/schema/cache"xmlns:tx="http://www.springframework.org/schema/task"--><tx:annotation-driven transaction-manager="transactionManager" /></beans>
    

mybatis-Mapper

  • <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="dao接口的全限定接口名"><!-- insert  update  delete  select  语句--><insert id="insertStudent">insert into t_spring value (#{id},#{name},#{email},#{age})</insert><select id="selectStudents" resultType="Student">select id,name,email,age from t_spring order by id desc</select>
    </mapper>
    

使用spring事务管理

  • 两步

    • 1.声明事务管理器

      • <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" ><!--指定数据源(连接的数据库)--><property name="dataSource" ref="dataSource" /></bean>
        
    • 2.开启事务注解驱动,告诉spring我们要使用注解管理事务,创建代理对象

      • 使用 注解 方式

        •    <!--2.开启事务注解驱动,告诉spring我们要使用注解管理事务,创建代理对象transaction-manager:表示事务管理器的对象id!!!!!!!!尾部是 tx的 不要选错了xmlns:tx="http://www.alibaba.com/schema/stat"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:tx="http://www.springframework.org/schema/cache"xmlns:tx="http://www.springframework.org/schema/task"--><tx:annotation-driven transaction-manager="transactionManager" />
          
      • 使用 配置文件 方式

        • <!--2.声明业务方法它的事务属性(隔离级别,传播行为,超时时间)id : 自定义名称,表示 <tx:advice>中的配置信息内容transaction-manager:事务管理器对象的id--><tx:advice id="myAdvice" transaction-manager="transactionManager"><!-- <tx:attributes> :配置事务属性   --><tx:attributes><!-- <tx:method name=""/> 给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性name:方法名称 1.完整的方法名称,不带有包名和类2.方法可以使用通配符,* 表示任意字符propagation : 传播行为isolation : 隔离级别rollback-for : 你指定的异常类名,全限定类名,发生异常一定回滚--><tx:method name="buyGoods" propagation="REQUIRED" isolation="DEFAULT"         rollback-for="java.lang.NullPointerException,com.bjpowernode.exception.MyException" /><!--使用通配符,指定很多的方法--><tx:method name="add*" propagation="REQUIRES_NEW" isolation="DEFAULT"/><tx:method name="modify*" /><tx:method name="remove*" /><!--查询 query,search.find--><tx:method name="query*" /><!--全部方法--><tx:method name="*" /></tx:attributes></tx:advice><!--配置aop--><aop:config><!--配置切入点表达式:指定哪些包中的类,要使用事务id:切入点表达式的名称,唯一值expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象com.bjpowernode.service--><aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/><!--配置增强器:关联advice 和 pointcutadvice-ref : 通知,上面的tx:advice那里的配置pointcut-ref : 切入点表达式的id--><aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/></aop:config>
          
  • java 代码

    • /*@Transactional(//传播行为(默认值 : Propagation.REQUIRED)propagation = Propagation.REQUIRED,//隔离级别(默认值 : Isolation.DEFAULT)isolation = Isolation.DEFAULT,//只读数据库(默认值 : false)readOnly = false,//抛出指定异常一定回滚(默认 抛出运行时异常回滚事务)//rollbackFor : 表示发生指定异常一定回滚//  处理逻辑是://      1.spring框架首先检查方法抛出的异常是不是在rollbackFor的属性值当中//          如果异常在rollbackFor列表中,不管是什么类型的异常,一定回滚//      2.如果你抛出的异常不在rollbackFor列表中,spring会判断异常是不是RuntimeException,//          如果是就回滚.rollbackFor = {NullPointerException.class,MyException.class}
      )*///使用的是事务控制的默认值, 默认传播行为是REQUIRED, 默认的隔离级别DEFAULT//默认 抛出运行时异常@Transactional@Overridepublic void buyGoods(int goodsId, int nums) {System.out.println("=====buyGoods()开始=====");//添加记录Sale sale = new Sale();sale.setGid(goodsId);sale.setNums(nums);saleDao.insertSale(sale);//更新库存Goods goods = goodsDao.selectGoods(goodsId);if (goods == null){//商品不存在throw new NullPointerException("编号是:"+ goodsId +"商品不存在");}else if (goods.getAmount() < nums){//商品库存不够throw new MyException("编号是:"+ goodsId +"商品库存不足哦");}//修改库存Goods buyGoods = new Goods();buyGoods.setId(goodsId);buyGoods.setAmount(goods.getAmount()-nums);goodsDao.updateGoods(buyGoods);System.out.println("=====buyGoods()结束=====");}
      

spring – web

  • 在spring中创建web项目

maven中添加依赖

  • <!-- 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.1-b03</version> <scope>provided</scope>
    </dependency><!--为了使用监听器对象,加入依赖-->
    <dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.22</version>
    </dependency>

使用 Spring 的监听器 ContextLoaderListener 需要在 web.xml文件中 注册该监听器

  • 
    <!--注册监听器ContextLoaderListener监听器被创建对象后,会读取/WEB-INF/applicationContext.xml文件为什么有读取这个文件? 因为在监听器中要创建ApplicationContext对象,需要加载配置文件路径ApplicationContext ac = new ClassPathXmlApplicationContext("文件路径啊");可以修改默认的文件位置,使用 context-param重新指定文件的位置配置监听器:目的是创建容器对象,创建了容器对象,就能把applicationContext.xml配置文件中所有对象都创建好用户发起请求就可以直接使用对象了-->
    <context-param><!--contextConfigLocation : 表示配置文件的路径--><param-name>contextConfigLocation</param-name><!--自定义配置文件的路劲--><param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
    

java代码

  •         //创建spring容器对象//ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");/*通过监听器将 WebApplicationContext对象放到 ServletContext应用域*///从ServletContext应用域中取出 WebApplicationContext对象/*WebApplicationContext ac = null;String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;Object attr = getServletContext().getAttribute(key);if (attr != null){ac =(WebApplicationContext)attr;}*///上面是自己写的获取spring容器对象,而框架中提供了这样的方法WebApplicationContext ac = null;ServletContext servletContext = getServletContext();ac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);System.out.println("容器对象===="+ ac);//获取serviceStudentService studentService = (StudentService) ac.getBean("studentService");Student student = new Student();student.setId(Integer.parseInt(id));student.setName(name);student.setEmail(email);student.setAge(Integer.valueOf(age));studentService.addStudent(student);//重定向response.sendRedirect(request.getContextPath()+"/result.jsp");
    

spring-mvc

SpringMVC就是一个Spring。 Spring是容器,ioc能够管理对象,使用, @Component, @Repository, @Service, @Controller
SpringMVC能够创建对象, 放入到容器中(SpringMVC容器), springmvc容器中放的是控制器对象,

我们要做的是 使用@Contorller创建控制器对象, 把对象放入到springmvc容器中, 把创建的对象作为控制器使用
这个控制器对象能接收用户的请求, 显示处理结果,就当做是一个servlet使用。

使用@Controller注解创建的是一个普通类的对象, 不是Servlet。 springmvc赋予了控制器对象一些额外的功能。

第一个spring-mvc项目

  • maven的pom.xml

    • <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bjpowernode</groupId><artifactId>ch01-hello-springmvc</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></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.1-b03</version><scope>provided</scope></dependency><!--springmvc 依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</version></dependency></dependencies><build></build>
      </project>
      
  • 需要在tomcat服务器启动后,创建DispatcherServlet对象的实例

    • <!--
      声明.注册springmvc的核心对象DispatcherServlet
      需要在tomcat服务器启动后,创建DispatcherServlet对象的实例为什么要创建DispatcherServlet对象的实例呢?因为DispatcherServlet在创建过程中,同时会创建springmvc容器对象读取springmvc的配置文件,把这个配置文件的对象都创建好,当用户发起请求时就可以直接使用对象了.servlet的初始化会执行 init()方法.`   DispatcherServlet在 init()中{//创建容器,读取配置文件WebApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//把容器对象放入到ServletContext中getServletContext().setAttribute(key,ctx);}
      启动tomcat报错.读取这个文件,Could not open ServletContext resource [/WEB-INF/myWeb-servlet.xml]springmvc创建对象时,读取配置文件默认是 /WEB-INF/ <servlet-name>-servlet.xml--><servlet><servlet-name>myWeb</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 自定义springmvc读取配置文件的位置 --><init-param><!-- springmvc配置文件的位置的属性 --><param-name>contextConfigLocation</param-name><!-- 值 : 一般指定在 classPath 下--><param-value>classpath:springmvc.xml</param-value></init-param><!--在tomcat启动后,创建Servlet对象load-on-startup : 表示tomcat启动后创建对象的顺序,值是一个整数,大于等于0的整数数值越小,tomcat创建对象的时间越早.--><load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping><servlet-name>myWeb</servlet-name><!--使用框架的时候,url-pattern可以使用两种值1.使用扩展名方式,语法 *.xxx, xxx是自定义的扩展名. 常用的方式 *.do , *.action , *.mvc等等http://localhost:8080/myWeb/some.dohttp://localhost:8080/myWeb/other.do2.使用斜杠 "/"--><url-pattern>*.do</url-pattern>
      </servlet-mapping>
      
  • 在 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"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:component-scan base-package="com.bjpowernode.controller"/><!--声明 springmvc框架中的视图解析器, 用于 设置 视图文件的重复路径--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 前缀 : 视图文件的路径 --><property name="prefix" value="/WEB-INF/view/" /><!--后缀 : 视图文件的扩展名--><property name="suffix" value=".jsp" /></bean>
      </beans>
      
  • java 代码

    • /*** @Controller : 创建处理器对象,对象放在springmvc容器中.* 位置 : 在类的上面*  和 Spring中讲的 @Service, @Controller.. 一样**  能处理请求的都是控制器(处理器),  MyController能处理请求,,叫做后端控制器(back controller)**/
      @Controller
      public class MyController {/*处理用户提交的请求,springmvc中是使用方法来处理的.方法是自定义的,可以有多种返回值,多种参数,方法名称自定义.*//*** 准备使用doSome方法处理some.do请求.* @RequestMapping : 请求映射,作用是把一个请求地址和一个方法绑定在一起*                  一个请求指定一个方法处理.*          属性 : 1.value 是一个String,表示请求的uri地址(some.do).*                  value的值必须是唯一的,不能重复,在使用时,推荐地址以 / 开始*          位置 : 1.在方法的上面,常用的.*                2.在类的上面* 说明 : 使用 @RequestMapping修饰的方法叫做处理器方法或者控制器方法.*       使用 @RequestMapping修饰的方法可以处理请求的,类似Servlet中的doGet,doPost.**       返回值 : ModelAndView**/@RequestMapping(value = {"/some.do","/first.do"})public ModelAndView doSome(){   //doGet()调用service请求处理//处理 some.do .//这里先不写service处理请求了//处理器之后ModelAndView mv = new ModelAndView();//添加数据      框架在请求的最后将数据放到了 request作用域了// request.setAttribute("msg","欢迎使用springmvc做web开发");mv.addObject("msg","欢迎使用springmvc做web开发");mv.addObject("fun","执行的是 doSome()方法");//指定视图,指定视图的完整路径//框架对视图执行的是转发的forward()操作,// request.getRequestDispatcher("/show.jsp").forward(request,response);//mv.setViewName("/show.jsp");//mv.setViewName("/WEB-INF/view/show.jsp");//mv.setViewName("/WEB-INF/view/other.jsp");//当配置了视图解析器后,可以使用逻辑名称(文件名字),指定视图mv.setViewName("show");//mv.setViewName("other");//返回 mvreturn mv;}@RequestMapping(value = {"/other.do","/second.do"})public ModelAndView doOther(){ModelAndView mv = new ModelAndView();mv.addObject("msg","欢迎使用springmvc做web开发");mv.addObject("fun","执行的是 doOther()方法");mv.setViewName("other");return mv;}
      }
      

注册声明过滤器,解决请求响应乱码问题

  •     <!--   在 web.xml文件中注册声明过滤器,解决请求响应乱码问题--><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><!--强制请求对象(HttpServletRequest)使用encoding设置的编码值--><init-param><param-name>forceRequestEncoding</param-name><param-value>true</param-value></init-param><!--强制响应对象(HttpServletResponse)使用encoding设置的编码值--><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>

@RequestMapping 注解

  • /*  @RequestMapping : 请求映射,作用是把一个请求地址和一个方法绑定在一起
    *                  一个请求指定一个方法处理.
    *          属性 : 1.value 是一个String,表示请求的uri地址(some.do).
    *                       value的值必须是唯一的,不能重复,在使用时,推荐地址以 / 开始
    *               2. method, 表示请求的方式,它的值 RequestMethod是枚举类型值.
    *                       例如 : 表示 get请求, RequestMethod.GET
    *                       表示 post请求, RequestMethod.POST
    *          位置 : 1.在方法的上面,常用的.
    *                2.在类的上面
    * 说明 : 使用 @RequestMapping修饰的方法叫做处理器方法或者控制器方法.
    *       使用 @RequestMapping修饰的方法可以处理请求的,类似Servlet中的doGet,doPost.
    *//*** @RequestMapping :*      value : 所有请求地址的公共部分,叫做模块名称*      位置 : 放在类的上面*/
    @RequestMapping("/user")
    @Controller
    public class MyController {@RequestMapping(value = "/some.do",method= RequestMethod.GET)public ModelAndView doSome(HttpServletRequest request,HttpServletResponse response,HttpSession session){   //doGet()调用service请求处理 括号里可以直接声明那些对象ModelAndView mv = new ModelAndView();mv.addObject("msg","使用springmvc做web开发==" +request.getParameter("name"));mv.addObject("fun","执行的是 doSome()方法");mv.setViewName("show");return mv;}}
    

接收请求参数

  •     /*** 逐个接收请求参数:*      要求: 处理器方法(控制器方法)的形参名必须和请求中的参数名一致*          同名的请求参数赋值给同名的形参* 框架接收请求参数 :*      1.使用request对象接收请求参数*          String strName = request.getParameter("name");*          String strAge = request.getParameter("age");*      2.springmvc框架通过 DispatcherServlet 调用 MyController的doSome()方法*          调用方法的时候,按名称对应,把接收的参数赋值给形参*          doSome(strName,Integer.ValueOf(strAge))*          框架会提供类型转换的功能,能把String转为int,long,float,double等等类型.**  HTTP状态 400 - 错误的请求  是客户端错误,表示在提交请求参数过程中,发生了问题*/
    @RequestMapping(value = "/recevieProperty.do", method = RequestMethod.POST)
    public ModelAndView doSome(String name, Integer age){ModelAndView mv = new ModelAndView();mv.addObject("myName",name);mv.addObject("myAge",age);mv.setViewName("show");return mv;
    }/***  请求中的参数名和处理器方法的形参名不一致怎么办?*  使用 @RequestParam : 逐个接收请求参数中,解决请求中参数名形参名不一样的问题*      属性 : 1.value 请求中的参数名称*            2.required 是一个boolean值,默认 true,*              true 表示请求中必须包含此参数*              false 表示 可以有也可以没有*      位置 : 在处理器方法的形参定义的前面*/
    @RequestMapping(value = "recevieParam.do",method = RequestMethod.POST)
    public  ModelAndView doRecevieParam(@RequestParam(value = "rname",required = false) String name,@RequestParam(value = "rage",required = false)Integer age){ModelAndView mv = new ModelAndView();mv.addObject("myName",name);mv.addObject("myAge",age);mv.setViewName("show");return mv;
    }/*** 处理器方法形参是 java 对象,这个对象的属性名和请求中的参数名一致的,* 框架会创建形参的java对象,给属性赋值,请求中的参数是name,框架会调用setName()**/
    @RequestMapping(value = "recevieObject.do",method = RequestMethod.POST)
    public  ModelAndView doRecevieObject(Student student){ModelAndView mv = new ModelAndView();mv.addObject("myName",student.getName());mv.addObject("myAge",student.getAge());mv.setViewName("show");return mv;
    }
    

处理器方法的返回值

返回ModelAndView,既有参数,又有视图

  • @RequestMapping(value = {"/some.do","/first.do"})public ModelAndView doSome(){   //doGet()调用service请求处理//处理 some.do .//这里先不写service处理请求了//处理器之后ModelAndView mv = new ModelAndView();//添加数据      框架在请求的最后将数据放到了 request作用域了// request.setAttribute("msg","欢迎使用springmvc做web开发");mv.addObject("msg","欢迎使用springmvc做web开发");mv.addObject("fun","执行的是 doSome()方法");//指定视图,指定视图的完整路径//框架对视图执行的是转发的forward()操作,// request.getRequestDispatcher("/show.jsp").forward(request,response);//mv.setViewName("/show.jsp");//mv.setViewName("/WEB-INF/view/show.jsp");//mv.setViewName("/WEB-INF/view/other.jsp");//当配置了视图解析器后,可以使用逻辑名称(文件名字),指定视图mv.setViewName("show");//mv.setViewName("other");//返回 mvreturn mv;}
    

返回String(两种形式)

  • 第一种 : 处理器方法返回String–表示逻辑视图名称,需要配置视图解析器
    • @RequestMapping(value = "/returnString-view.do", method = RequestMethod.POST)
      public String doReturnStringView(String name, Integer age, HttpServletRequest request){//自己手工添加数据到request作用域request.setAttribute("myName",name);request.setAttribute("myAge",age);// show : 逻辑视图名称,项目中配置了视图解析器// 框架对视图执行 forward转发操作return "show";
      }
      
  • 第二种 : 处理器方法返回的是String ,String 表示数据的,不是视图.

    • @RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=UTF-8")
      @ResponseBody
      public String doStringData(String name, Integer age){return "Hello SpringMVC 返回 String对象, 表示数据";
      }
      
  • 怎么区分 返回的是 什么 ?
    •   /***  处理器方法返回的是String ,String 表示数据的,不是视图.*  区分返回值String是数据,还是视图,看有没有@ReesponseBody注解*  如果有@ResponseBody注解,返回String就是数据,反之就是视图**  默认使用"text/plain;charset=ISO-8859-1"作为contentType,导致中文乱码,*  解决方法 : 给 @RequestMapping增加一个属性 produces,使用这个属性指定新的contentType.** 返回对象框架的处理流程 :*      1.框架会把返回 String 类型,调用框架中的ArrayList<HttpMessageConverter>的                  write()方法*          检查哪个HttpMessageConverter接口的实现类能处理 String 类型的数据--                    StringHttpMessageConverter*      2.框架会调用实现类的write(),StringHttpMessageConverter的write()方法*          把字符按照指定的方式进行编码  text/plain;charset=ISO-8859-1*      3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成**/
      

返回void,响应ajax请求

  • /***  处理器方法返回void,响应ajax请求*/
    @RequestMapping(value = "/returnVoid-ajax.do", method = RequestMethod.POST)
    public void doReturnVoidAjax(String name, Integer age, HttpServletResponse response){//响应ajax,使用json做数据格式//假设 service 调用完成了.使用Student表示处理结果Student student = new Student();student.setName(name);student.setAge(age);String json = "";//把 student 转为 json格式的数据if (student != null){ObjectMapper om = new ObjectMapper();try {json = om.writeValueAsString(student);System.out.println("student转换为的json :"+json);} catch (JsonProcessingException e) {e.printStackTrace();}}//响应PrintWriter out = null;response.setContentType("application/json;charset=utf-8");try {out= response.getWriter();out.print(json);out.flush();} catch (IOException e) {e.printStackTrace();}finally{out.close();}
    }
    

返回一个对象

  • /***  处理器方法返回一个 Student,通过框架转为 json 格式的字符串,响应 ajax请求**  @ResponseBody :*      作用 : 把处理器方法返回对象转为json后,通过HttpServletResponse输出给浏览器.*      位置 : 方法定义的上面,和其他注解没有顺序的关系**  返回对象框架的处理流程 :*      1.框架会把返回Student类型,调用框架中的ArrayList<HttpMessageConverter>的write()方法*          检查哪个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter*      2.框架会调用实现类的write(),MappingJackson2HttpMessageConverter的write()方法*          把"哈哈哈哈"的student对象转换为json,调用Jackson的ObjectMapper实现转为json*          application/json;charset-UTF-8;*      3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成*/
    @RequestMapping("returnStudentJson.do")
    @ResponseBody
    public Student doStudentJsonObject(String name,Integer age){//调用 service 获取请求结果数据,student对象表示结果数据Student student = new Student();student.setName("哈哈哈哈");student.setAge(1111);return student; //会被框架转为json格式的字符串 @ResponseBody
    }
    

返回一个List集合

  • /***  处理器方法返回一个List集合,通过框架转为 json 格式的字符串,响应 ajax请求** 返回对象框架的处理流程 :*      1.框架会把返回List<Student>类型,调用框架中的ArrayList<HttpMessageConverter>的write()方法*          检查哪个HttpMessageConverter接口的实现类能处理List<Student>类型的数据--MappingJackson2HttpMessageConverter*      2.框架会调用实现类的write(),MappingJackson2HttpMessageConverter的write()方法*          把List<Student>对象转换为json,调用Jackson的ObjectMapper实现转为json*          application/json;charset-UTF-8;*      3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成*/
    @RequestMapping("returnStudentJsonArray.do")
    @ResponseBody
    public List<Student> doStudentJsonObjectArray(String name, Integer age){//调用 service 获取请求结果数据,student对象表示结果数据List<Student> studentList = new ArrayList<>();Student student1 = new Student();student1.setName("宫本武藏");student1.setAge(18888);Student student2 = new Student();student2.setName("天下无双");student2.setAge(1);studentList.add(student1);studentList.add(student2);// [{"name":"宫本武藏","age":18888},{"name":"天下无双","age":1}]return studentList; //会被框架转为json格式的字符串(数组形式) @ResponseBody
    }
    

注意 : 将Object数据转为JSON(String,User对象,List集合等等)

  • 需要由消息转换器 HttpMessageConverter 完成。而转 换器的开启,需要由来完成。

  • <!--添加注解驱动-->
    <mvc:annotation-driven />
    

web.xml中 spring-mvc的核心对象DispatcherServlet的uri-pattern导致的静态资源无法访问

  • <servlet><servlet-name>myWeb</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 自定义springmvc读取配置文件的位置 --><init-param><!-- springmvc配置文件的位置的属性 --><param-name>contextConfigLocation</param-name><!-- 值 : 一般指定在 classPath 下--><param-value>classpath:springmvc.xml</param-value></init-param><!--在tomcat启动后,创建Servlet对象load-on-startup : 表示tomcat启动后创建对象的顺序,值是一个整数,大于等于0的整数数值越小,tomcat创建对象的时间越早.--><load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping><servlet-name>myWeb</servlet-name><!--使用框架的时候,url-pattern可以使用两种值1.使用扩展名方式,语法 *.xxx, xxx是自定义的扩展名. 常用的方式 *.do , *.action , *.mvc等等http://localhost:8080/myWeb/some.dohttp://localhost:8080/myWeb/other.do2.使用斜杠 "/"--><!--使用框架的时候, uri-pattern可以使用两种值1.使用扩展名方式,语法 *.xxx, xxx是自定义的扩展名.常用的方式 *.do不能使用 *.jsphttp://localhost:8080/ch05/some.dohttp://localhost:8080/ch05/other.do2.使用 " / "当你的项目中使用了 /, 它会代替 tomcat中的 default.导致所有的静态资源都给了 DispatcherServlet处理. 默认情况下,DispatcherServlet没有处理静态资源的能力,没有控制器对象能处理静态资源的访问,所以静态资源(html, js, 图片, css)都是404动态资源some是可以访问的,因为我们程序中有MyController控制器对象,能够处理some请求.--><url-pattern>/</url-pattern>
    </servlet-mapping>
    

解决方案

  • 方案一 :在 springmvc.xml文件中

    • <!--那我们又要让springmvc的核心对象DispatcherServlet 去处理用户发来的请求(使用 @RequestMapper注解)配置的路径又是 / (表示该项目下所有请求路径都走他,),导致访问静态资源 404 问题第一种解决方案 :需要在 springmvc配置文件加入 <mvc:default-servlet-handler>原理是 : 加入这个标签后,框架会创建控制器对象 DefaultServletHttpRequestHandler(类似我们自己写的 MyController).
      DefaultServletHttpRequestHandler这个对象可以把接收的请求转发给 tomcat的default这个servlet--><mvc:default-servlet-handler /><!--default-servlet-handler 和 @RequestMapping注解有冲突,需要加入 annotation-driven解决问题--><!--添加注解驱动--><mvc:annotation-driven />
      
  • 方案二 : 在 springmvc.xml文件中

    • <!--第二种处理静态资源的方式:映射静态资源<mvc:resources /> 加入后框架会创建 ResourceHttpRequestHandler这个处理器对象.让这个对象处理静态资源的访问,不依赖tomcat服务器.属性 :mapping : 访问静态资源的uri地址,使用通配符 **location : 静态资源在你项目中的目录位置.
      images/** : 表示 images/p1.jpg , images/user/login.gif ,images/order/history/p1.jpg
      -->
      <mvc:resources mapping="/images/**" location="/images/" />
      <mvc:resources mapping="/html/**" location="/html/" />
      <mvc:resources mapping="/js/**" location="/js/" /><!--上面要写三个,我们把静态资源放到一个文件夹下面,这样就可以只配一个了-->
      <mvc:resources mapping="/static/**" location="/static/" />
      

转发和重定向

  • 转发

    • /**
      *  处理器方法返回 ModelAndView,实现转发forward
      *  语法 : setViewName("forward:视图文件的完整路径")
      *  forward 特点 : 不和视图解析器一同使用,就当项目中没有视图解析器
      * @return
      */
      @RequestMapping(value = "/doForward.do",method= RequestMethod.POST)
      public ModelAndView doForward(){ModelAndView mv = new ModelAndView();mv.addObject("msg","欢迎使用springmvc做web开发");mv.addObject("fun","执行的是 doForward()方法");//mv.setViewName("forward:/WEB-INF/view/show.jsp");//使用 forward可以转发到视图解析器以外的页面mv.setViewName("forward:/hello.jsp");return mv;
      }
      
  • 重定向

    •  /***  处理器方法返回 ModelAndView,实现转发 redirect*  语法 : setViewName("redirect:视图文件的完整路径")*  redirect 特点 : 不和视图解析器一同使用,就当项目中没有视图解析器** 框架对重定向的操作:*  1.框架会把Model中的简单类型的数据,转为String使用,作为hello.jsp的get请求参数使用*      目的是在 doRedirect.do 和 hello.jsp 两次请求之间传递数据*      (我们可以取出来)**  2.在目标 hello.jsp页面可以使用参数集合对象 ${param}获取请求参数值,或者request.getParameter()*      ${param.myName}*      ${pageContext.request.getParameter("myAge")}**  3.重定向不能访问 WEB-INF 下的资源的*/@RequestMapping(value = "/doRedirect.do",method= RequestMethod.POST)public ModelAndView doRedirect(String name, Integer age){ModelAndView mv = new ModelAndView();mv.addObject("myName",name);mv.addObject("myAge",age);//重定向mv.setViewName("redirect:/hello.jsp");http://localhost:8080/ch08/hello.jsp?myName=wangwu&myAge=18return mv;}
      

异常 @ControllerAdvice @ExceptionHandler

  • 两步 在 dispatcherServlet.xml(springmvc)的配置文件中

      1. 声明注解扫描器
      2. 注解驱动
      
      <context:component-scan base-package="com.bjpowernode.handler" />
      <mvc:annotation-driven />
      
  • java代码

    • /*** @ControllerAdvice : 控制器增强(也就是说给控制器类增加功能---异常处理功能)*          位置 : 在类的上面*  特点 : 必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器*      指定@ControllerAdvice所在的包名*/
      @ControllerAdvice
      public class GlobalExceptionHandler {//定义方法来处理发生的异常/*处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有 ModelAndView,String,void,对象类型的返回值形参 : Exception , 表示Controller中抛出的异常对象通过形参可以获取发生的异常信息.@ExceptionHandler(异常的class) : 表示异常的类型,当发生此类异常的时候,由当前方法处理如果 @ExceptionHandler() 什么都不写,表示处理其他异常,只能有一个.*/@ExceptionHandler(value = NameException.class)public ModelAndView doNameException(Exception exception){//处理 NameException的异常./*异常发生需要处理的逻辑1.需要把异常记录下来,记录到数据库,日志文件.记录日志发生的事件,哪个地方发生的,异常错误内容.2.发生通知,把异常的信息通过邮件,短信,微信发生给相关人员.3.给用户友好的提示.*/ModelAndView mv = new ModelAndView();mv.addObject("msg","名字设定了是'zhangsan',不然就抛异常");mv.addObject("ex",exception);mv.setViewName("nameError");return mv;}// 处理AgeException@ExceptionHandler(value = AgeException.class)public ModelAndView doAgeException(Exception exception){//处理 NameException的异常./*异常发生需要处理的逻辑1.需要把异常记录下来,记录到数据库,日志文件.记录日志发生的事件,哪个地方发生的,异常错误内容.2.发生通知,把异常的信息通过邮件,短信,微信发生给相关人员.3.给用户友好的提示.*/ModelAndView mv = new ModelAndView();mv.addObject("msg","年龄超过80就抛异常");mv.addObject("ex",exception);mv.setViewName("ageError");return mv;}// 处理其他未知@ExceptionHandler()public ModelAndView doOtherException(Exception exception){//处理 NameException的异常./*异常发生需要处理的逻辑1.需要把异常记录下来,记录到数据库,日志文件.记录日志发生的事件,哪个地方发生的,异常错误内容.2.发生通知,把异常的信息通过邮件,短信,微信发生给相关人员.3.给用户友好的提示.*/ModelAndView mv = new ModelAndView();mv.addObject("msg","未知异常");mv.addObject("ex",exception);mv.setViewName("defaultError");return mv;}
      }
      

拦截器

  • 拦截器和过滤器类似,功能方向侧重点不同。 过滤器是用来过滤器请求参数,设置编码字符集等工作。
    拦截器是拦截用户的请求,做请求做判断处理的。

  • 拦截器是全局的,可以对多个Controller做拦截。
    一个项目中可以有0个或多个拦截器, 他们在一起拦截用户的请求。
    拦截器常用在:用户登录处理,权限检查, 记录日志。

  • 在 dispatcherServlet.xml(springmvc)的配置文件中 声明拦截器

    java类实现HandlerInterceptor接口

    • <!--声明拦截器 : 拦截器可以有0个或多个在框架中保存多个拦截器是 ArrayList按照声明的先后顺序放到 ArrayList中.--><mvc:interceptors><!--声明第一个拦截器--><mvc:interceptor><mvc:mapping path="/**"/><!--配置排除拦截请求(优先级高于 上面的拦截请求)--><!--表示需要放过的请求--><mvc:exclude-mapping path=""/><!--声明拦截器对象--><bean class="com.bjpowernode.handler.MyInterceptor" /></mvc:interceptor><!--声明第二个拦截器--><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.bjpowernode.handler.MyInterceptor2" /></mvc:interceptor></mvc:interceptors>
      
  • 多个拦截器执行顺序

    • 多个拦截器:
      第一个拦截器preHandle=true , 第二个拦截器preHandle=true 111111-拦截器的MyInterceptor的preHandle()
      22222-拦截器的MyInterceptor的preHandle()
      =====执行MyController中的doSome方法=====
      22222-拦截器的MyInterceptor的postHandle()
      111111-拦截器的MyInterceptor的postHandle()
      22222-拦截器的MyInterceptor的afterCompletion()
      111111-拦截器的MyInterceptor的afterCompletion()---------------------------------------------------
      第一个拦截器preHandle=true , 第二个拦截器preHandle=false111111-拦截器的MyInterceptor的preHandle()
      22222-拦截器的MyInterceptor的preHandle()
      111111-拦截器的MyInterceptor的afterCompletion()----------------------------------------------------------
      第一个拦截器preHandle=false , 第二个拦截器preHandle=true|false111111-拦截器的MyInterceptor的preHandle()
      
    • 拦截器和过滤器的区别

      • 1.过滤器是servlet中的对象,  拦截器是框架中的对象
        2.过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor
        3.过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。拦截器是用来验证请求的,能截断请求。
        4.过滤器是在拦截器之前先执行的。
        5.过滤器是tomcat服务器创建的对象拦截器是springmvc容器中创建的对象
        6.过滤器是一个执行时间点。拦截器有三个执行时间点
        7.过滤器可以处理jsp,js,html等等拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容
        8.拦截器拦截普通类方法执行,过滤器过滤servlet请求响应
        
  • java代码

    • //拦截器类 : 拦截用户的请求
      public class MyInterceptor implements HandlerInterceptor {private long dateTime = 0;/***  perHandle叫做预处理方法*      重要:是整个项目的入口,门户.当preHandle返回true,请求可以被处理.*      preHandle返回false,请求到此方法就截至了.*  参数 : Object handler : 被拦截的控制器对象**  返回值 boolean*      true : 请求是通过了拦截器的验证,可以执行处理器方法*           拦截器的 MyController的preHandle()*           ==== MyController中的doSome执行了====*           拦截器的 MyController的postHandle()*           拦截器的 MyController的afterCompletion()**      false : 请求没有通过拦截器的验证,请求到达拦截器就截至了,没有去执行处理器的方法*            拦截器的 MyController的preHandle()**  特点:*      1.方法在控制器方法 (MyController的doSome)之前执行的.*          用户的请求首先到达此方法**      2.在这个方法中可以获取请求的信息,验证请求是否符合要求.*          可以验证用户是否登录,验证用户是否有权限访问某个连接地址(url),*          如果验证失败,可以截断请求,请求不能被处理.*          如果验证成功,可以放行请求,此时控制器方法才能执行.*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("拦截器的 MyController的preHandle()");dateTime = System.currentTimeMillis();//给浏览器一个返回结果//request.getRequestDispatcher("/tips.jsp").forward(request,response);return true;}/*** postHandle : 后处理方法.* 参数 :*  Object handler : 被拦截的处理器对象 (MyController)*  ModelAndView modelAndView : 处理器方法的返回值**  特点:*      1.在处理器方法之后执行的 (MyController的doSome()之后)*      2.能够获取到处理器方法的返回值ModelAndView,可以修改 ModelAndView中*          的数据和视图,可以影响到最后的执行结果.*      3.主要是对原来的执行结果进行二次修正.*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("拦截器的 MyController的postHandle()");//对原来的doSome()方法执行结果.需要调整if (modelAndView != null){//修改数据modelAndView.addObject("myDate", SimpleDateFormat.getDateTimeInstance().format(new Date()));//修改视图modelAndView.setViewName("other");}}/*** afterCompletion : 最后执行的方法* 参数 :*      Object handler :被拦截的处理器对象*      Exception ex : 程序中发生的异常*  特点 :*      1.在请求处理完成后执行, 框架中规定是 当你的视图处理完成后,对视图执行了 forward(),就认为请求处理完成了,*      2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收.*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("拦截器的 MyController的afterCompletion()");long eTime = System.currentTimeMillis();System.out.println("计算从 preHandle() 到 请求处理完成的时间是 : "+ (eTime - dateTime));}
      }
    • //拦截器类 : 拦截用户的请求
      public class MyInterceptor2 implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("222拦截器的 MyController的preHandle()");return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("222拦截器的 MyController的postHandle()");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("222拦截器的 MyController的afterCompletion()");}
      }
      

ssm整合

maven的pom.xml文件

  • <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bjpowernode</groupId><artifactId>ch07-ssm</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></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.1-b03</version><scope>provided</scope></dependency><!--springMVC 依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</version></dependency><!--spring 事务用到的--><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.22</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.22</version></dependency><!-- Spring AOP支持--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version></dependency><!--jackson 依赖--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency><!--mybatis 和 spring集成的依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency><!--mybatis 依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><!---mysql 驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!--数据库连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><!--所在的目录--><includes><!--包括目录下的.properties,.xml 文件都会扫描到--><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></pluginManagement></build>
    </project>

web.xml

  • <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 欢迎页,默认进入index controller --><welcome-file-list><welcome-file>/</welcome-file></welcome-file-list><!--注册中央调度器--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:conf/dispatcherServlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!--注册spring的监听器--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:conf/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--HiddenHttpMethodFilter  resultful风格--><filter><filter-name>HiddenHttpMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter><filter-mapping><filter-name>HiddenHttpMethodFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!--注册字符集过滤器--><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>
    

jdbc.properties

  • jdbc.url=jdbc:mysql://localhost:3306/db_spring?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
    jdbc.username=root
    jdbc.password=root
    

mybatis-config.xml

  • <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!--settings : 控制mybatis全局行为--><settings><!--设置mybatis输出日志--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><!--起别名--><typeAliases><package name="com.bjpowernode.bean"/></typeAliases><!--sql mapper(sql映射文件)的位置--><mappers><!-- name 是包名,这个包中的所有mapper.xml文件一次都能加载使用package的要求:1. mapper文件名称和dao接口必须完全一样,包括大小写2.mapper文件和dao接口必须在同一目录--><package name="com.bjpowernode.dao"/></mappers>
    </configuration>
    

mybatisMapper.xml

  • <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.bjpowernode.dao.StudentDao"><select id="selectStudents" resultType="Student">select id,name ,age from t_student order by id desc</select><insert id="insertStudent" >insert into t_student(name,age) values (#{name},#{age})</insert>
    </mapper>
    

applicationContext.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"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"><!--spring配置文件 : 声明service, dao, 工具类等对象--><!--声明jdbc文件位置--><context:property-placeholder location="classpath:conf/jdbc.properties" /><!--声明数据源,连接数据库--><!-- 如果使用 spring容器控制事务 DriverMapperDataSource --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close"><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><!--声明 SqlSessionFactoryBean : 创建 SqlSessionFactory--><bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:conf/mybatis-config.xml" /></bean><!--声明mybatis的扫描器,去创建dao对象--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /><property name="basePackage" value="com.bjpowernode.dao" /></bean><!--扫描 注解 @Service所在的包的位置--><context:component-scan base-package="com.bjpowernode.service"/><!--事务配置 : 注解配置 , aspectj配置--><!--1.声明事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--指定数据源(连接的数据库)--><property name="dataSource" ref="druidDataSource" /></bean><!--2.开启事务注解驱动,告诉spring我们要使用注解管理事务,创建代理对象transaction-manager:表示事务管理器的对象id!!!!!!!!尾部是 tx的 不要选错了xmlns:tx="http://www.alibaba.com/schema/stat"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:tx="http://www.springframework.org/schema/cache"xmlns:tx="http://www.springframework.org/schema/task"--><!--配置事务--><tx:advice id="txAdvice" transaction-manager="transactionManager"><!--配置事务属性--><tx:attributes><!--方法名称可以使用通配符*--><tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/><tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/><tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/><tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/><tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/><tx:method name="do*" propagation="REQUIRED" rollback-for="Exception"/><tx:method name="*" propagation="REQUIRED" read-only="true"/></tx:attributes></tx:advice><!--配置事务切入点--><aop:config><!--就是将配置好的事务与业务方法绑定--><aop:pointcut expression="execution(* com.bjpowernode.crm..service.*.*(..))" id="allMethodPointcut"/><aop:advisor advice-ref="txAdvice" pointcut-ref="allMethodPointcut"/></aop:config></beans>
    

DispatcherServlet.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:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--spring配置文件,声明controller和其他web相关的对象--><!--解决中央调度器不能访问静态资源--><mvc:resources mapping="/static/**" location="/static/" /><!--静态资源处理  二选一--><mvc:default-servlet-handler/><!--注册注解扫描器--><context:component-scan base-package="com.bjpowernode.controller" /><!--注册注解驱动--><mvc:annotation-driven /><!--视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" ><property name="prefix" value="/WEB-INF/jsp/" /><property name="suffix" value=".jsp" /></bean><!--拦截器--><mvc:interceptors><mvc:interceptor><!--配置拦截请求--><mvc:mapping path="/settings/**"/><mvc:mapping path="/workbench/**"/><!--配置排除拦截请求(优先级高于 上面的拦截请求)--><mvc:exclude-mapping path="/settings/qx/user/toLogin.do"/><mvc:exclude-mapping path="/settings/qx/user/login.do"/><!--配置拦截器类--><bean class="com.bjpowernode.crm.settings.web.interceptor.LoginInterceptor"/></mvc:interceptor></mvc:interceptors>
    </beans>
    

java.Controller层

  • package com.bjpowernode.controller;import com.bjpowernode.bean.Student;
    import com.bjpowernode.service.StudentService;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.servlet.ModelAndView;import javax.annotation.Resource;
    import java.util.List;@Controller
    @RequestMapping("/student")
    public class StudentController {@Resourceprivate StudentService studentService;//注册学生@RequestMapping("/addStudent")public ModelAndView addStudent(Student student){String tips = "注册失败.";ModelAndView mv = new ModelAndView();//调用service处理studentint nums = studentService.addStudent(student);if (nums > 0){//注册成功tips = "学生[" + student.getName() + "]注册成功";}//添加数据mv.addObject("tips",tips);//指定结果页面mv.setViewName("result");return mv;}//查询学生 ajax@RequestMapping("/queryStudent")@ResponseBodypublic List<Student> queryStudent(){//参数检查,简单的数据处理List<Student> students = studentService.findStudents();return students;}
    }

java.service接口

  • package com.bjpowernode.service;import com.bjpowernode.bean.Student;import java.util.List;public interface StudentService {int addStudent(Student student);List<Student> findStudents();
    }

java.service实现类

  • package com.bjpowernode.service.impl;import com.bjpowernode.bean.Student;
    import com.bjpowernode.dao.StudentDao;
    import com.bjpowernode.service.StudentService;
    import org.springframework.stereotype.Service;import javax.annotation.Resource;
    import java.util.List;@Service
    public class StudentServiceImpl implements StudentService {@Resourceprivate StudentDao studentDao;@Overridepublic int addStudent(Student student) {int nums= studentDao.insertStudent(student);return nums;}@Overridepublic List<Student> findStudents() {List<Student> studentList = studentDao.selectStudents();return studentList;}
    }

java.dao层

  • package com.bjpowernode.dao;import com.bjpowernode.bean.Student;import java.util.List;public interface StudentDao {int insertStudent(Student student);List<Student> selectStudents();}

java.bean

  • package com.bjpowernode.bean;import java.util.Objects;public class Student {//属性名 和 表中字段名 保持一致private Integer id;private String name;private Integer age;public Student() {}public Student(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return Objects.equals(id, student.id) && Objects.equals(name, student.name) && Objects.equals(age, student.age);}@Overridepublic int hashCode() {return Objects.hash(id, name, age);}
    }

mybatis+spring+springmvc ssm整合相关推荐

  1. (转)SpringMVC学习(四)——Spring、MyBatis和SpringMVC的整合

    http://blog.csdn.net/yerenyuan_pku/article/details/72231763 之前我整合了Spring和MyBatis这两个框架,不会的可以看我的文章MyBa ...

  2. 【BackEnd--SSM 框架详解】Mybatis+Spring+SpringMVC学习笔记(完整详细版)

    BackEnd 学习笔记 1 Java 2 SSM框架(Mybatis+Spring+SpringMVC) 3 SpringBoot(SpringBoot 3.x+MybatisPlus) 4 Spr ...

  3. 【Spring+SpringMVC+Mybatis】利用SSM整合,完成用户登录、注册、修改密码系统

    近年来,由于Struts2+Hibernate3+Spring3,这套SSH框架,Struts2屡次爆出安全漏洞,Hibernate就只会推行它HQL那套而越来越远离SQL查询关系数据库的本质,所以S ...

  4. myeclipes10.7+maven+myBatis+spring+springMvc

    SSM框架详细整合教程(Spring+SpringMVC+MyBatis) 2016年02月26日 01:50:21 程序员囧辉 阅读数:60951 版权声明:本文为博主原创文章,未经博主允许不得转载 ...

  5. mybatis spring springMVC

    unit10-mybatis框架 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZIyKRxA-1611577268155)(第二阶段讲义04.assets/a0a2 ...

  6. springMVC——SSM整合(IDEA 搭建简单 ssm 框架最详细最简单教程)

    为开发一个测试程序,特搭建一个简单的ssm框架,因为网上看到很多都是比较老旧的教程,很多包都不能用了,eclipes搭建并且其中还附带了很多的其他东西,所以特此记录一下mac中idea搭建过程. 以下 ...

  7. spring+springmvc+hibernate 整合

    三大框架反反复复搭了很多次,虽然每次都能搭起来,但是效率不高.最近重新搭了一次,理顺了思路,整理了需要注意的地方,分享出来. 工具:Eclipse(jdk 1.7) spring和hibernate版 ...

  8. Spring+SpringMVC+Hibernate整合(封装CRUD操作)

    前言:当前Web项目开发的框架主流应该非Spring+SpringMVC+Hibernate莫属,不管是工作还是学习中涉及框架技术,首先是要搭建一套运行环境,虽然网上框架整合的教程很多,但我还是输出此 ...

  9. Spring+SpringMVC+Hibernate整合操作数据库 概述

    概述 Hibernate是一款优秀的ORM框架,能够连接并操作数据库,包括保存和修改数据.Spring MVC是Java的web框架,能够将Hibernate集成进去,完成数据的CRUD.Hibern ...

最新文章

  1. C# 字符串 数据类型 判断 与特定规则验证
  2. 程序员的你是否熟练掌握Chrome开发者工具?
  3. C++中4种强制类型转换 ?
  4. 牛客多校2 - Fake Maxpooling(线性递推gcd+单调队列)
  5. php+tp框架+API,【路由】利用Thinkphp路由实现API开发版本管理
  6. 关闭linux系统中读写页缓存,Linux文件系统FAQ
  7. python来构建多层网络
  8. c语言类静态数据成员函数,鸡啄米:C++编程入门系列之二十一(C++程序设计必知:类的静态成员)...
  9. 干干净净用java_十四步 干干净净卸载Oracle
  10. php请求图片,PHP - 发送GET请求并获取图片作为回报
  11. 浅析移动互联浪潮之由来
  12. 杭州市建筑物矢量数据(Shp格式+带高度)
  13. 光模块基础知识【快速入门】02
  14. 2022 DSCTF首届数字空间安全攻防大赛 部分题解
  15. 手写数字图像识别-SVM算法投票法实现多分类
  16. 《马云点评创业》读书笔记
  17. 德·摩根定律的验证(De Morgan’s Laws)
  18. 控制面板设置java_win10系统打开java控制面板的具体技巧
  19. MATLAB强化学习实战(十三) 使用强化学习智能体训练Biped机器人行走
  20. Procmon.exe —— 强大的系统监视工具

热门文章

  1. php直播表情美颜的实现,如何在直播中实现优质的美颜SDK效果
  2. 【DirectX11】【学习笔记(10)】混合
  3. 大数据破危险品物流难题 危化品污染有望“圈治”
  4. 【使用SqliteSpy访问Sqlite3数据库】
  5. 【青少年编程】【二级】小瓢虫找妈妈
  6. Linux下安装配置各种软件和服务
  7. MSDC 4.3 接口规范(24)
  8. uview基本配置,在HubildX中如何配置uni-app相关的组件
  9. 只会写代码的程序员不是好程序员
  10. shp文件显示 c语言,上传并在地图中显示Shp文件