SSM详解

MyBatis

搭建运行环境
1-->导入jar包,包括mybatis的核心包和依赖包以及jdbc连接包
2-->配置mybatis.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--设置数据库连接参数-->
<properties resource="jdbc.properties">
<!--若引入外部配置文件,则不需要单独配置property标签-->
<property name="username" value="user_name"/>
	 <property name="password" value="123456"/>
</properties>

<!--设置日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>

<typeAliases>
<!--为单个实体类设置别名-->
<!--<typeAlias type="com.yjd.pojo.Flower" alias="f"></typeAlias>-->
<!--为整个包下实体类设置别名,包下别名为类名,不区分大小写-->
<package name="com.yjd.pojo"/>
</typeAliases>

<!--配置mybatis中数据库连接环境-->
<environments default="mysql">
<environment id="mysql">
<!--配置事务,与jdbc中事务保持一致-->
<transactionManager type="JDBC"></transactionManager>
<!--动态配置数据库连接的driver、url、username、password-->
	 <!--数据库连接参数获取顺序:
    1、在properties 元素体内指定的属性首先被读取。
	 2、然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性				文件,并覆盖已读取的同名属性。
	 3、最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
qlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
	 // ... or ...
	 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
	 -->
<dataSource type="POOLED">
    <!--
    可为占位符指定默认值,若无法读取到具体值,则使用默认值
    <property name="username" value="${username:my_user}"/>
    默认关闭状态,可在properties标签中启用
    <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
    -->
    <property name="driver" value="${mysql_driver}"/>
    <property name="url" value="${mysql_url}"/>
    <property name="username" value="${mysql_username}"/>
    <property name="password" value="${mysql_password}"/>
</dataSource>
</environment>
</environments>

<!--扫描FlowerMapper.xml才能解析使用-->
<mappers>
<!--为包下单独类-->
<mapper resource="com/yjd/mapper/FlowerMapper.xml"></mapper>
<mapper resource="com/yjd/mapper/FlowerMapper2.xml"></mapper>
<mapper resource="com/yjd/mapper/FlowerMapper3.xml"></mapper>
<!--设置包下所有类全部扫描-->
<package name="com.yjd.mapper"/>
</mappers>
</configuration>

3-->配置持久层多个mapper.xml,如FlowerMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--定位操作位置-->
<mapper namespace="Flower.a">
<!--标签代表操作类型
id代表方法名称    
resultType代表返回值类型,集合时直接写泛型   
parameterType参数类型可省略
-->
<select id="selectList" resultType="Flower">
select * from flower
</select>

<select id="selectOne" resultType="Flower">
select * from flower where fid=29
</select>

<select id="selectMap" resultType="Map">
select * from flower
</select>

<!--
参数接收
基本数据类型或String类型时使用param1
一个实体类对象时使用对象的属性名#{属性名}
一个Map集合对象时使用Map中的key #{key}
-->

<!--
参数接收时可以使用${param1/属性名/key}
使用$相当于字符串的拼接,所以需要注意拼接的格式  "'鲜花'"
使用#相当于使用占位符
-->
<!--单个参数-->
<select id="selectOne1" resultType="Flower">
select * from flower where fid=#{param1}
</select>

<!--单个实体类对象参数-->
<select id="selectOne2" resultType="Flower">
select * from flower where fid=#{fid} and fname=#{fname}
</select>

<!--单个Map集合参数-->
<select id="selectOne3" resultType="Map">
select * from flower where fid=#{a} and fname=#{b}
</select>

<!--模糊查询    concat拼接/拼接好再传递-->
<select id="selectOne4" resultType="Flower">
select * from flower where fname like concat('%',#{param1},'%')
</select>

//crud
<insert id="insertOne">
insert into flower values(default,#{fname},#{price},#{production})
</insert>

<delete id="deleteOne">
delete from flower where fid=#{param1}
</delete>

<update id="updateOne">
update flower set fname=#{fname} where fid=#{fid}
</update>

<select id="selectList" resultType="flower">
select * from flower
</select>

</mapper>

4-->配置log4j.properties文件
log4j.rootLogger=error,logfile,stdout
//设置log打印sql语句的权限,Flower为mapper.xml中namespace属性值
log4j.logger.Flower=debug

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=E:/Object/logs/log4j.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd hh:mm:ss} %l %F %p %m%n


log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout

5-->配置jdbc.properties文件-->与jdbc数据库连接时相同
6-->使用mybatis做增删改查操作
package com.yjd.text;

import com.yjd.pojo.Flower;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: Ada
 * @date: 2021/6/2 10:23
*/
public class Test {

 public static void main(String[] args) throws IOException {

     //创建SqlSession对象
     //解析xml文件配置信息
     InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
     //获得SqlSessionFactory工厂对象
     SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
     //获得SqlSession对象
     SqlSession sqlSession = build.openSession();

     //查询的三种方式
     List<Flower> list = sqlSession.selectList("Flower.a.selectList");
     System.out.println(list);
     Flower one = sqlSession.selectOne("Flower.a.selectOne");
     System.out.println(one);
     //key为数据库字段
     Map<Object, Object> map = sqlSession.selectMap("Flower.a.selectMap", "fid");
     System.out.println(map);

     //传递单个参数
     Flower flower = sqlSession.selectOne("Flower.b.selectOne1", 31);
     System.out.println(flower);
     //传递单个实体类对象
     Flower flower1 = new Flower();
     flower1.setFid(30);
     flower1.setFname("修改");
     Flower flower2 = sqlSession.selectOne("Flower.b.selectOne2", flower1);
     System.out.println(flower2);
     //传递一个Map集合
     Map<String, Object> map1 = new HashMap<>();
     map1.put("a", 29);
     map1.put("b", "成功");
     Object o = sqlSession.selectOne("Flower.b.selectOne3", map1);
     System.out.println(o);
     //模糊查询
     Object aa = sqlSession.selectOne("Flower.b.selectOne4", "成");
     System.out.println(aa);

     System.out.println("========================");
     //CRUD
     Flower flower3 = new Flower();
     flower3.setFname("新增");
     flower3.setPrice(23);
     flower3.setProduction("中国");
     sqlSession.insert("Flower.c.insertOne", flower3);

     sqlSession.delete("Flower.c.deleteOne", 32);

     Flower flower4 = new Flower();
     flower4.setFname("change");
     flower4.setFid(30);
     int update = sqlSession.update("Flower.c.updateOne", flower4);
     System.out.println(update);

     List<Object> objects = sqlSession.selectList("Flower.c.selectList");
     System.out.println(objects);


     //添加和事务提交
     //1、SqlSession sqlSession = build.openSession(true);
     //2、sqlSession.commit();
     sqlSession.commit();
     sqlSession.close();

     //引入本地DTD
 }
}

Mapper代理/接口绑定
-->实体类变量接收数据库中对应列的数据的两种方式:自动映射和手动映射
-->自动映射
-->mybatis中定义的实体类变量名与数据库中的列名相同时直接自动映射
-->手动映射两种方式
-->1、不相同时需要在sql语句中为列名起别名,别名与实体类变量名称相同
-->2、如下使用resultMap标签,主键列要写在非主键列前,有dtd格式要求
<mapper namespace="com.yjd.mapper.ClazzMapper">

<select id="selectClazz" resultMap="cla">
select * from clazz where cid=#{param1}
</select>

<resultMap id="cla" type="clazz">
<!--
result 应用于非主键列、id应用于主键列
column对应数据库列名
property对应实体类属性名
-->
	<id column="id" property="cid"></id>
<result column="name" property="cname"></result>
</resultMap>

</mapper>

-->定义接口
public interface FlowerMapper {

List<Flower> selectMore(int id, String name);

List<Flower> selectMore2(Flower flower1, Flower flower2);

//为参数取别名,相当于传递Map作为参数
//mapper接口中方法不能重载
List<Flower> selectMore3(@Param("a") int id, @Param("b") String name);

}

-->定义mapper.xml
-->动态代理中的参数传递
<mapper namespace="com.yjd.mapper.FlowerMapper">

<!--
获得主键自增值
1、线程不安全
<insert id="新增方法" useGeneratedKeys="true" keyProperty="fid">
useGeneratedKeys:开启主键自增值
keyProperty:将主键值放入到类的fid属性中
2、线程安全
order:表示语句执行之后获得
<selectKey order="AFTER" keyProperty="fid" resultType="int">
   select @@identity
</selectKey>
-->
<!--1种方式,建议使用-->
<insert id="add" useGeneratedKeys="true" keyProperty="fid">
insert into t_checkgroup(code,name,sex,helpCode,remark,attention)
values
(#{code},#{name},#{sex},#{helpCode},#{remark},#{attention})
</insert>

<!‐‐第2种方式,未测试‐‐>
<insert id="add" parameterType="com.yjd.pojo.user">
<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
	select LAST_INSERT_ID()/select @@identity
</selectKey>
	insert into t_checkgroup(code,name,sex,helpCode,remark,attention)
	values
	(#{code},#{name},#{sex},#{helpCode},#{remark},#{attention})  
</insert>

<delete id="删除方法">

</delete>

<update id="修改方法">

</update>

<!--paramN代表传入的第几个参数,参数为对象时,可以使用paramN.变量名获得值-->
<!--传入两个基本数据类型/String-->
<select id="selectMore" resultType="Flower">
select * from flower where fid=#{param1} and fname=#{param2}
</select>

<!--传入两个对象,取两个对象内的变量-->
<select id="selectMore2" resultType="Flower">
select * from flower where fid=#{param1.fid} and fname=#{param2.fname}
</select>

</mapper>

-->mapper代理使用
public static void main(String[] args) throws IOException {
   //解析mybatis.xml文件
   InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
   //获得SqlSessionFactory工厂
   SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
   //获得SqlSession对象
   SqlSession sqlSession = build.openSession();
   //获得接口对象
   FlowerMapper mapper = sqlSession.getMapper(FlowerMapper.class);
 
   List<Flower> list = mapper.selectMore(31, "a");
   System.out.println(list);
   Flower flower1 = new Flower();
   flower1.setFid(31);
   Flower flower2 = new Flower();
   flower2.setFname("a");
   List<Flower> list1 = mapper.selectMore2(flower1, flower2);
   System.out.println(list1);
   sqlSession.close();
}

-->mappers设置
<mappers>
<!--扫描单个mapper.xml文件-->
<!--<mapper resource="com/yjd/mapper/FlowerMapper.xml"></mapper>-->

<!--找到包下所有接口,找到xml名称与接口名称相同的xml文件进行扫描。注意**接口与xml文件名称相同-->
<!--
基于包进行xml扫描
1、接口名称与xml名称一致
2、xml中namespace属性与接口全路径名称一致
3、crud标点中的id属性与接口中方法名称相同
-->
<!--扫描包下所有mapper.xml文件-->
<package name="com.yjd.mapper"/>
</mappers>
动态SQL
-->OGNL表达式
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.yjd.mapper.FlowerMapper">
<!--动态SQL-->
<!--if标签、set标签-->
<!--set标签去除最后一个,-->
<update id="updateOne">
update flower
<set>
<if test="param2 !=null and param2 != ''">
    fname=#{param2},
</if>
<if test="param3 !=null and param3 != ''">
    production=#{param3}
</if>
where fid=#{param1}
</set>
</update>

<!--where标签-->
<!--where标签去除第一个and-->
<select id="selectMore4" resultType="Flower">
select * from flower
<where>
<if test="fname !=null and fname !=''">
    and fname=#{fname}
</if>
<if test="production !=null and production !=''">
    and production=#{production}
</if>
</where>
</select>

<!--chose标签、when标签-->
<!--相当于if...else语句-->
<select id="selectMore5" resultType="Flower">
select * from flower
<where>
<choose>
    <when test="param1 !=null and param1 !=''">
        and fname=#{param1}
    </when>
    <when test="param2 !=null and param2 !=''">
        and production=#{param2}
    </when>
</choose>
</where>
</select>

<!--定义投影列,使用include便签生效如下
	<include refid="sql1"/>           
-->
<sql id="sql1">
	fid,fname,price
</sql>

<!--前缀和后缀-->
<update id="update">
update flower
<trim prefix="set" suffixOverrides=",">
<if test="param2 != null and param2 != ''">
fname=#{param2}
</if>
</trim>
where fid=#{param1}
</update>

<--
foreach标签遍历集合中元素  
-->
<delete id="deleteMore">
delete from flower where fid in
<foreach collection="list" item="e" open="(" close=")" separator=",">
#{e}
</foreach>
</delete>

<!--模糊查询bind拼接-->
<!--concat('%',#{param1},'%')-->
<select id="selectMore6" resultType="Flower">
select <include refid="sql1"></include> from flower where fname like
<bind name="bind" value="'%'+param1+'%'"/>
#{bind}
</select>

</mapper>
多表查询
-->业务代码方式
for (Student t : list) {
 int cid = t.getCid();
 Clazz clazz = clazzMapper.selectClazz(cid);
 t.setClazz(clazz);
 System.out.println(t);
}

-->N+1
<!--N+1-->
<select id="selectAll" resultMap="res1">
	select sid,name sname,sex,cid from student
</select>
<resultMap id="res1" type="student">
 <result column="name" property="sname"></result>
 <result column="cid" property="cid"></result>
 <association property="clazz" column="cid" javaType="clazz" 		select="com.yjd.mapper.ClazzMapper.selectClazz">
 </association>
</resultMap>

<!--N+1-->
<select id="selectAll" resultMap="res2">
	select * from clazz
</select>
<resultMap id="res2" type="clazz">
 <result column="cid" property="cid"></result>
 <collection property="list" column="cid" ofType="student" select="com.yjd.mapper.StudentMapper.selectMore">
 </collection>
</resultMap>
//N+1
List<Student> list = studentMapper.selectAll();
System.out.println(list);
List<Clazz> list1 = clazzMapper.selectAll();
System.out.println(list1);

-->单条SQL多表查询
<!--单条SQL多表查询-->
<select id="selectAll2" resultMap="res3">
select * from student s join clazz c on s.cid=c.cid
</select>
<resultMap id="res3" type="clazz">
 <id column="cid" property="cid"></id>
 <result column="cname" property="cname"></result>
 <result column="cteacher" property="cteacher"></result>
  <--集合使用collection标签ofType属性-->
 <collection property="list" ofType="student">
 <id column="sid" property="sid"></id>
 <result column="name" property="sname"></result>
 <result column="sex" property="sex"></result>
 <result column="cid" property="cid"></result>
	</collection>
</resultMap>
<!--单条SQL多表查询-->
<select id="selectAll2" resultMap="res2">
	select * from student s join clazz c on s.cid=c.cid
</select>
<resultMap id="res2" type="Student">
 <id column="sid" property="sid"></id>
 <result column="name" property="sname"></result>
 <result column="sex" property="sex"></result>
 <result column="cid" property="cid"></result>
  <--单个对象使用association标签javaType属性-->
 <association property="clazz" javaType="clazz">
 <id column="cid" property="cid"></id>
 <result column="cname" property="cname"></result>
 <result column="cteacher" property="cteacher"></result>
</association>
</resultMap>
 
//单条SQL多表查询
List<Student> list = studentMapper.selectAll2();
System.out.println(list);
List<Clazz> list1 = clazzMapper.selectAll2();
System.out.println(list1);

-->设置延迟加载
<settings>
 <setting name="logImpl" value="LOG4J"/>
 <!--开启mybatis中懒加载-->
 <setting name="lazyLoadingEnabled" value="true"/>
 <!--关闭每一个属性的懒加载-->
 <setting name="aggressiveLazyLoading" value="false"/>
</settings>

获得主键自增值
-->插入一条数据后直接返回当前插入数据的主键值,将值赋给传入对象的Id属性
<insert id="insertInfo" useGeneratedKeys="true" keyProperty="Id">
 insert into area(region,have,value)
 values (#{region},#{have},#{value})
</insert>

Info info = new Info(null,"3","2","3");
int i = infoDao.insertInfo(info);
System.out.println(info.getId());`
缓存
-->一级缓存默认开启,称为SqlSession缓存
-->二级缓存默认不开启,称为SqlSessionFactory缓存,满足多个用户sql语句的缓存效果。全局缓存默认开启,只需要mapper.xml	 中配置,全局缓存设置在mybatis.xml中的setting标签中设置
<!--开启SqlSessionFactory二级缓存,全部sql都开启-->
<cache/>
设置useCache="false"属性可以关闭当条查询的缓存
<select id="selectAll2" resultMap="res3" useCache="false">
-->缓存查询顺序
二级缓存-->一级缓存-->数据库-->保存到一级-->关闭/提交SqlSession一级缓存时将缓存数据存放到二级缓存
注解开发
@Insert("SQL语句")
@Delete("SQL语句")
@Update("SQL语句")
@Select("SQL语句")
List<Clazz> selectAll3();

-->适用于单表简单查询,写注解后不需要配置.xml文件,只适用于当前添加注解的方法

Spring

IOC-->控制反转
   -->不使用new对象的方式,由spring容器创建对象,实现松耦合
DI-->依赖注入
  -->为实例对象的变量属性赋值
AOP-->面向切面编程
   -->增加程序的扩展性,可在当前切点前后增加通知,以扩展功能
TX-->声明式事务
  -->对于事务的控制交由框架处理,底层使用aop技术,不能try...catch有问题代码,否则事务不生效
创建类实例IOC
-->四种创建方式(IOC)
1、无参bean
2、有参bean
3、静态工厂
4、非静态工厂
-->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-4.0.xsd">

 <!--构造方法创建实现类实例-->
 <!--无参构造创建实现类实例-->
 <bean id="stu" class="com.yjd.service.impl.StudentServiceImpl"></bean>

<!--有参构造创建实现类实例-->
<bean id="stu2" class="com.yjd.service.impl.StudentServiceImpl">
     <!--name属性中的值与构造参数中的值名称相同-->
     <!--当一个构造参数的形参相同,但顺序不同时,会调用后一个构造参数-->
     <!--可以指定index/type属性对应形参中参数的顺序,为唯一确定的构造方法调用-->
     <!--type属性只能写基本数据类型,如需写引用数据类型,需要全路径名java.lang.String-->
     <constructor-arg name="id" value="0" type="int"></constructor-arg>
     <constructor-arg name="name" value="yang"></constructor-arg>
     <constructor-arg name="sex" value="男"></constructor-arg>
</bean>

<!--使用工厂创建实现类实例-->
<!--param为工厂方法的形参名称,value为实参--> 
 <!--工厂创建实例的方法为静态方法-->
 <bean id="s" class="com.yjd.factory.Factory" factory-method="getStatic">
  	<constructor-arg name="param" value="stu"></constructor-arg>
 </bean>

<!--工厂创建实例的方法为非静态方法-->
 <bean id="t" class="com.yjd.factory.Factory"></bean>
 <bean id="u" factory-bean="t" factory-method="getUnStatic">
     <constructor-arg name="param" value="stu"></constructor-arg>
 </bean>

</beans>

-->test
public class Test {

public static void main(String[] args) {

     //xml文件解析,文件中所有bean标签全部生效,生成对应实现类实例
     ClassPathXmlApplicationContext app = new 		   ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");

     //通过bean中的id属性获得配置文件中已生成的实现类的实例
     //获得无参构造创建的实例
     StudentService stu1 = app.getBean("stu", StudentService.class);
     stu1.aa();

     //获得有参构造创建的实例
     StudentService stu = app.getBean("stu2", StudentService.class);
     stu.aa();

     //工厂模式静态
     StudentService s = app.getBean("s", StudentService.class);
     s.aa();
     
     //工厂模式非静态
     StudentServiceImpl u = app.getBean("u", StudentServiceImpl.class);
     u.aa();

}
}

依赖注入DI
-->为已存在的实例对象中的变量赋值
-->四种方式
1、构造器方式
2、set方式
3、自动注入方式
4、数组/集合赋值
<?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-4.0.xsd">

<!--构造器方式赋值-->
<bean id="cla" class="com.yjd.pojo.Clazz">
 <constructor-arg name="cid" value="1">
 </constructor-arg>
 <constructor-arg name="cname" value="S110">
 </constructor-arg>
 <constructor-arg name="cteacher" value="yang">
 </constructor-arg>
</bean>

<!--set方式赋值-->
<!--必须提供此变量的get&set方法才能进行赋值-->
<!--value:基本数据类型	ref:实例类对象-->
<bean id="stu" class="com.yjd.pojo.Student">
 <property name="sid" value="1">
 </property>
 <property name="sname" value="小明">
 </property>
 <property name="sex" value="男">
 </property>
 <!--依赖注入-->
 <property name="clazz" ref="cla">
 </property>
</bean>

<!--自动注入-->
<!--
使用自动注入后,当前实例中的属性会按查找规则找到对应的数据自动注入,注入的属性为对象
autowire:
1、byName:当bean中的id属性名称与class类中的变量名称相同时,自动注入
2、byType:当bean生成类实例的类型与当前class类属性中需要的类型相同时,自动注入,注意只能有一个所需实例类型的bean
3、constructor:必须有单独的构造方法供构造器自动注入使用,否则无法注入
-->
<!--自动注入与set/构造器方式可以联合使用-->
<bean id="cla" class="com.yjd.pojo.Clazz">
 <constructor-arg name="cid" value="1">
 </constructor-arg>
 <constructor-arg name="cname" value="S110">
 </constructor-arg>
 <constructor-arg name="cteacher" value="yang">
 </constructor-arg>
</bean>
<bean id="auto" class="com.yjd.pojo.Student" autowire="constructor">
 <property name="sid" value="1">
 </property>
 <property name="sname" value="小明">
 </property>
 <property name="sex" value="男">
 </property>
</bean>

<!--数组与集合赋值,name为类中变量名称-->
<!--map集合赋值方式较特殊-->
 
<!--数组-->
<bean id="ar" class="com.yjd.pojo.Student">
 <property name="arr">
    <array>
        <value>a</value>
        <value>b</value>
        <value>c</value>
    </array>
 </property>
</bean>
 
<!--List集合-->
<bean id="li" class="com.yjd.pojo.Student">
 <property name="list">
    <list>
        <value>a</value>
        <value>b</value>
        <value>c</value>
    </list>
 </property>
</bean>
 
<!--Set集合-->
<bean id="se" class="com.yjd.pojo.Student">
 <property name="set">
    <set>
        <value>a</value>
        <value>b</value>
        <value>c</value>
    </set>
 </property>
</bean>
 
<!--Map集合-->
<bean id="ma" class="com.yjd.pojo.Student">
 <property name="map">
    <map>
        <entry>
            <key><value>1</value></key>
            <value>a</value>
        </entry><entry>
            <key><value>2</value></key>
            <value>b</value>
        </entry><entry>
            <key><value>3</value></key>
            <value>c</value>
        </entry>
    </map>
 </property>
</bean>

</beans>

bean单例/多例
public class Test {
  public static void main(String[] args) {

        /**
         * singleton:单例模式
         * prototype:多例模式
         * Spring默认为单例模式
         * 单例模式下,new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml")时会创建一		   次对象
         * 多例模式下,app.getBean("li", Student.class)时就创建对象
         * */
     ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");

         Student stu1 = app.getBean("li", Student.class);
     Student stu2 = app.getBean("li", Student.class);

         System.out.println(stu1==stu2);

}
}

-->bean中添加scope标签控制单例/多例模式
<bean id="li" class="com.yjd.pojo.Student" scope="singleton">
  <property name="list">
         <list>
             <value>a</value>
             <value>b</value>
             <value>c</value>
         </list>
   </property>
</bean>
与MyBatis整合
-->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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.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
     http://www.springframework.org/schema/tx
     https://www.springframework.org/schema/tx/spring-tx.xsd">

<!--引入jdbc.properties文件-->
 <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
     
 <!--Spring配置jdbc-->
 <bean id="jdbc" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName" value="${mysql_driver}">
     </property>
     <property name="url" value="${mysql_url}">
     </property>
     <property name="username" value="${mysql_username}">
     </property>
     <property name="password" value="${mysql_password}">
     </property>
 </bean>
     
 <!--获得SqlSessionFactory工厂-->
 <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
     <property name="dataSource" ref="jdbc">
     </property>
     <property name="typeAliasesPackage" value="com.yjd.pojo">
     </property>
 </bean>
     
 <!--配置Mappers扫描-->
 <bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     <property name="sqlSessionFactoryBeanName" value="factory">
     </property>
     <property name="basePackage" value="com.yjd.mapper">
     </property>
 </bean>

 <!--简化编程,降低耦合-->
 <!--一举两得,既可以得到UserMapper对象在当前实例中使用,又可以IOC方式创建UserServiceImpl对象-->
 <bean id="users" class="com.yjd.service.impl.UserServiceImpl">
     <property name="userMapper" ref="userMapper">
     </property>
 </bean>
</beans>

-->servlet
@WebServlet(urlPatterns = "/yjd/LoginServlet")
public class LoginServlet extends HttpServlet {
 
 private UserService userService;
 
 @Override
 public void init() throws ServletException {
 
     //解析文件并初始化一次
     ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");
     userService = app.getBean("users", UserService.class);
 }
 
 @Override
 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
     String uKey = req.getParameter("ukey");
     String pwd = req.getParameter("pwd");
     
     User one = userService.findOne(uKey, pwd);
     System.out.println(one);
 
     if (one != null) {
         resp.sendRedirect(req.getContextPath() + "/success.jsp");
     } else {
         req.getRequestDispatcher("/success.jsp").forward(req, resp);
     }
     
 }
}

-->UserServiceImpl
public class UserServiceImpl implements UserService {
 
 private UserMapper userMapper;
 
 public UserMapper getUserMapper() {
     return userMapper;
 }
 
 public void setUserMapper(UserMapper userMapper) {
     this.userMapper = userMapper;
 }
 
 @Override
 public User findOne(String uKey, String pwd) {
     
     return userMapper.selectOne(uKey, pwd);
     
 }
}

代理模式
-->静态代理和动态代理
-->动态代理:在不修改源代码的情况下对程序进行扩展
-->JDK动态代理,必须要有接口
-->代理类
public class MyProxy {
 
 public Object getProxy(Object obj) {
     return Proxy.newProxyInstance(MyProxy.class.getClassLoader(), new Class[]{MyCalculate.class}, new InvocationHandler() {
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             YjdExpand.log(method.getName(), args[0], args[1]);
         
             Object invoke = method.invoke(obj, args);
         
             return invoke;
         
         }
     });
 }
}

-->代理类生成class文件
package com.yjd.proxy;

import java.io.FileOutputStream;
import java.io.IOException;

import sun.misc.ProxyGenerator;

public class Util {
	
   /** 
     *  Util.writeProxyClassToHardDisk("E:/$Proxy11.class",new FD1().getClass().getInterfaces() );
  */  
 public static void writeProxyClassToHardDisk(String path,Class[]  cla) {  

     byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", cla);
       
     FileOutputStream out = null;  
       
     try {  
         out = new FileOutputStream(path);  
         out.write(classFile);  
         out.flush();  
     } catch (Exception e) {  
         e.printStackTrace();  
     } finally {  
         try {  
             out.close();  
         } catch (IOException e) {  
             e.printStackTrace();  
         }  
     }  
 }  

}

-->使用代理类
public class Test {
 
 public static void main(String[] args) {
 
     MyProxy myProxy = new MyProxy();
     MyCalculate proxy = (MyCalculate) myProxy.getProxy(new MyCalculateImpl());
     int jia = proxy.jia(1, 2);
     System.out.println("结果为:" + jia);
 
     Util.writeProxyClassToHardDisk("E:/$Proxy11.class", new MyCalculateImpl().getClass().getInterfaces());
     
 }
}

-->JVM中代理类代码
import com.yjd.service.*;
import java.lang.reflect.*;

public final class $Proxy11 extends Proxy implements MyCalculate{
 
 private static Method m1;
 private static Method m2;
 private static Method m3;
 private static Method m0;
 private static Method m4;
 
 public $Proxy11(final InvocationHandler invocationHandler) {
     super(invocationHandler);
 }
 
 public final boolean equals(final Object o) {
     try {
         return (boolean)super.h.invoke(this, $Proxy11.m1, new Object[] { o });
     }
     catch (Error | RuntimeException error) {
         throw;
     }
     catch (Throwable t) {
         throw new UndeclaredThrowableException(t);
     }
 }
 
 public final String toString() {
     try {
         return (String)super.h.invoke(this, $Proxy11.m2, null);
     }
     catch (Error | RuntimeException error) {
         throw;
     }
     catch (Throwable t) {
         throw new UndeclaredThrowableException(t);
     }
 }
 
 public final int jia(final int n, final int n2) {
     try {
         return (int)super.h.invoke(this, $Proxy11.m3, new Object[] { n, n2 });
     }
     catch (Error | RuntimeException error) {
         throw;
     }
     catch (Throwable t) {
         throw new UndeclaredThrowableException(t);
     }
 }
 
 public final int hashCode() {
     try {
         return (int)super.h.invoke(this, $Proxy11.m0, null);
     }
     catch (Error | RuntimeException error) {
         throw;
     }
     catch (Throwable t) {
         throw new UndeclaredThrowableException(t);
     }
 }
 
 public final int jian(final int n, final int n2) {
     try {
         return (int)super.h.invoke(this, $Proxy11.m4, new Object[] { n, n2 });
     }
     catch (Error | RuntimeException error) {
         throw;
     }
     catch (Throwable t) {
         throw new UndeclaredThrowableException(t);
     }
 }
 
 static {
     try {
         $Proxy11.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
         $Proxy11.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
         $Proxy11.m3 = Class.forName("com.yjd.service.MyCalculate").getMethod("jia", Integer.TYPE, Integer.TYPE);
         $Proxy11.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
         $Proxy11.m4 = Class.forName("com.yjd.service.MyCalculate").getMethod("jian", Integer.TYPE, Integer.TYPE);
     }
     catch (NoSuchMethodException ex) {
         throw new NoSuchMethodError(ex.getMessage());
     }
     catch (ClassNotFoundException ex2) {
         throw new NoClassDefFoundError(ex2.getMessage());
     }
 }
}

-->CGLIB动态代理
-->代理类
public class CGLIBProxy {
 
 public Object getCGLIBProxy(Object obj) {
     Enhancer enc = new Enhancer();
     //设置代理类父类
     enc.setSuperclass(obj.getClass());
     //设置回调函数
     enc.setCallback(new MethodInterceptor() {
        /**
             * 参数一:代理对象
             * 参数二:目标方法反射对象
             * 参数三:目标方法参数
             * 参数四:代理方法反射对象
          */
         @Override
         public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
             //扩展代码
             YjdExpand.log(method.getName(), objects[0], objects[1]);
             Object invoke = method.invoke(obj, objects);
             return invoke;
         }
     });
 
     Object o = enc.create();
     return o;
 }  
}
-->使用
public class TestCGLIBProxy {
 
 public static void main(String[] args) {
 
     //获得CGLIBProxy动态代理对象
     MyCalculateImpl cglibProxy = (MyCalculateImpl) new CGLIBProxy().getCGLIBProxy(new MyCalculateImpl());
     int jia = cglibProxy.jia(1, 2);
     System.out.println(jia);
     
 }
 
}
面向切面编程AOP
-->在不修改源码的基础上进行功能扩展,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术

-->基本概念
1Aspect(切面):通常是一个类,里面可以定义切入点和通知
2JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
3Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
4Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
5、AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基	于接口,后者基于子类

-->四种通知:
1、前置通知
2、后置通知
3、环绕通知(可在切点前和后执行,有返回值,被前后通知包围)
4、异常通知(切点运行中出错才会执行,使用异常通知时不能捕获异常,否则无法触发异常通知)

横向切面(代理对象):前置通知+切点+后置通知
执行顺序:连接点顺序执行-->前置通知-->环绕前-->切点-->环绕后-->后置通知

-->AOP实现扩展的两种方式:
1Schema_based基于接口,切点参数与返回值易获取
2AspectJ基于对象,获得切点参数和返回值时很麻烦
涉及参数使用Schema-based,不涉及参数使用AspectJ

Schema_based方式
-->Schema_based方式
-->前置通知
public class BeforeAdvice implements MethodBeforeAdvice {

@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {

System.out.println("bb的前置通知");

}
}
-->后置通知
public class AfterAdvice implements AfterReturningAdvice {

/**
     * o:切点方法的返回值
     * method:切点中方法对象
     * objects:切点中参数列表
     * o1:切点所在类的对象
     * */
 @Override
 public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {

 }
}
-->环绕通知
public class Around implements MethodInterceptor {

 @Override
 public Object invoke(MethodInvocation methodInvocation) throws Throwable {
     System.out.println("环绕前"+methodInvocation.getMethod());
     //注意**此处固定写法,执行切点方法
     Object proceed = methodInvocation.proceed();
     System.out.println("环绕后");
     return proceed;

 }
}
-->异常通知
public class Throw implements ThrowsAdvice {

 //固定写法,切点运行异常执行
 public void afterThrowing(Exception ex) throws Throwable {
     System.out.println("--异常通知--");
 }

}

-->ApplicationContext.xml配置
<!--创建实现类对象-->
<bean id="stu" class="com.yjd.service.impl.StudentServiceImpl"></bean>

<!--创建前置通知对象-->
<bean id="bef" class="com.yjd.advice.BeforeAdvice"></bean>
<!--创建后置通知对象-->
<bean id="aft" class="com.yjd.advice.AfterAdvice"></bean>
<!--创建环绕通知对象-->
<bean id="aro" class="com.yjd.advice.Around"></bean>
<!--创建异常通知对象-->
<bean id="thr" class="com.yjd.advice.Throw"></bean>

<!--AOP设置-->
<aop:config>
 <!--设置切点-->
 <aop:pointcut id="pot" expression="execution(* com.yjd.service.impl.StudentServiceImpl.bb())"/>
 <!--切点与前置通知对象关联-->
 <aop:advisor advice-ref="bef" pointcut-ref="pot"></aop:advisor>
 <!--切点与后置通知对象关联-->
 <aop:advisor advice-ref="aft" pointcut-ref="pot"></aop:advisor>
 <!--切点与环绕通知对象关联-->
 <aop:advisor advice-ref="aro" pointcut-ref="pot"></aop:advisor>
 <!--切点与异常通知对象关联-->
 <aop:advisor advice-ref="thr" pointcut-ref="pot"></aop:advisor>

 <!--切点设置多种方式-->
 <!--impl包中所有类中所有方法都作为切点-->
 <!--<aop:pointcut id="pot" expression="execution(* com.yjd.service.impl.*.*(..))"/>-->
 <!--类中所有方法都作为切点-->
 <!--<aop:pointcut id="pot" expression="execution(* com.yjd.service.impl.StudentServiceImpl.*(..))"/>-->
 <!--指定类下所有名称为bb的方法都作为切点-->
 <!--<aop:pointcut id="pot" expression="execution(* com.yjd.service.impl.StudentServiceImpl.bb(..))"/>-->
 <!--指定类下指定方法作为切点-->
 <!--<aop:pointcut id="pot" expression="execution(* com.yjd.service.impl.StudentServiceImpl.bb(int,double,String))"/>-->
</aop:config>

	<!--false为JDK动态代理,true为CGLIB动态代理
 	若目标类中没有声明接口,则spring会自动使用CGLIB动态代理
	-->
	<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>

-->切点使用+通知
package com.yjd.test;

import com.yjd.service.StudentService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

public static void main(String[] args) {

  //解析xml文件配置
  ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");
  //此处需注意,stu对象为代理对象,为接口实现类,不能使用接口其他实现类声明
  StudentService stu = app.getBean("stu", StudentService.class);
  //stu.aa();
  stu.bb();
  //stu.cc();
}
}

AspectJ方式
-->AspectJ

-->通知类
package com.yjd.advice;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author: Ada
 * @date: 2021/6/9 9:33
*/

/**
 * AspectJ可以将四种通知放在一个通知类中
 * */
public class AspectJAdvice {

 public void beforeAdvice() {
     System.out.println("--前置通知--");
 }

 public void afterAdvice() {
     System.out.println("--后置通知--");
 }

 public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable {
     System.out.println("--环绕通知前--");
     Object proceed = point.proceed();
     System.out.println("--环绕通知后--");
     return proceed;
 }

 public void throwsAdvice() {
     System.out.println("--异常通知--");
 }
}

-->ApplicationContext.xml文件配置
<!--实现类对象-->
<bean id="stu" class="com.yjd.service.impl.StudentServiceImpl"></bean>
<!--创建通知对象-->
<bean id="aspect" class="com.yjd.advice.AspectJAdvice"></bean>
<aop:config>
 <aop:aspect ref="aspect">
     <!--设置切点-->
     <aop:pointcut id="ap" expression="execution(* com.yjd.service.impl.StudentServiceImpl.bb())"/>
     <!--前置通知-->
     <aop:before method="beforeAdvice" pointcut-ref="ap"></aop:before>
     <!--无论切点运行是否报错,后置通知都会执行-->
     <aop:after method="afterAdvice" pointcut-ref="ap"></aop:after>
     <!--切点运行报错,后置通知不执行-->
     <aop:after-returning method="afterAdvice" pointcut-ref="ap"></aop:after-returning>
     <!--环绕通知-->
     <aop:around method="aroundAdvice" pointcut-ref="ap"></aop:around>
     <!--异常通知-->
     <aop:after-throwing method="throwsAdvice" pointcut-ref="ap"></aop:after-throwing>
 </aop:aspect>
</aop:config>

-->使用切点+通知
package com.yjd.test;

import com.yjd.service.StudentService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

 public static void main(String[] args) {

     //解析xml文件配置
     ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("classpath:ApplicationContext2.xml");
     //此处需注意,stu对象为代理对象,为接口实现类,不能使用接口其他实现类声明
     StudentService stu = app.getBean("stu", StudentService.class);
     //stu.aa();
     stu.bb();
     //stu.cc();
 }
}

LomBok常用注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uebV4tVc-1654393801942)(C:\Users\纵横\AppData\Roaming\Typora\typora-user-images\image-20210608183852358.png)]

-->lombok更换工作空间后需按上图设置生效
@Data 注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
@Setter :注解在属性上;为属性提供 setting 方法
@Getter :注解在属性上;为属性提供 getting 方法
@Log4j :注解在类上;为类提供一个属性名为log 的log4j 日志对象
@NoArgsConstructor :注解在类上;为类提供一个无参的构造方法
@AllArgsConstructor :注解在类上;为类提供一个全参的构造方法
@Cleanup : 可以关闭流
@Builder : 被注解的类加个构造者模式
@Synchronized : 加个同步锁
@SneakyThrows : 等同于try/catch 捕获异常
@NonNull : 如果给参数加个这个注解 参数为null会抛出空指针异常
@Value : 注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法
声明式事务TX
-->执行两条或两条以上增删改操作需要事务操控,事务分为编程式事务和声明式事务(由框架管理,配置即可)
-->底层使用AOP面向切面编程,使用tx通知,业务层不要捕捉异常,否则程序出错无法回滚

-->ApplicationCOntext.xml配置
1、不使用事务注解的情况下
<!--Spring中事务的管理对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"  ref="jdbc"></property>
</bean>
<!--为方法添加事务通知-->
<tx:advice id="ad" transaction-manager="transactionManager">
 <!--attributes可省略?-->
 <tx:attributes>
     <tx:method name="move"/>
 </tx:attributes>
</tx:advice>
<!--事务底层使用AOP完成-->
<!--通过AOP给指定切点增加事务-->
<aop:config>
 <aop:pointcut id="pt1" expression="execution(* com.yjd.service.impl.*.*(..))"/>
 <aop:advisor advice-ref="ad" pointcut-ref="pt1"></aop:advisor>
</aop:config>

2、使用注解
<!--事务驱动注册-->
<tx:annotation-driven></tx:annotation-driven>
<!--创建事务管理对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"  ref="jdbc"></property>
</bean>
<!--在类/方法上添加@Transactional注解,指定切点-->

-->设置事务属性
-->使用注解的情况下在@Transactional属性中设置,未使用注解的情况下在<tx:method name="move"/>属性中设置
-->time-out:超时

-->read-only:只读

-->propagation:事务传播行为
-->事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行
-->methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,	这就是由methodB的事务传播行为决定的。
1、required(默认):方法B必须在事务中运行,如果方法A有事务,则方法B在方法A中运行,否则将开启一个新事务
2、supports:方法B不需要运行在事务方法中,方法A有无事务,方法B都在A中运行
3、mandatory:方法B必须在事务中运行,如方法A不是事务方法,则抛出一个异常
4、requires_new:当事务方法A中调用事务方法B时,挂起事务方法A,执行事务方法B,方法B执行结束后再释放执行事务方法A
5、not_supported:方法B必须在非事务状态下,事务方法A调用方法B后,挂起事务方法A以非事务状态执行方法B
6、never:方法A与方法B均不能是事务方法,否则报错
7、nested:事务方法A调用事务方法B后,如方法A报错,直接回滚到方法B执行,如方法B报错,直接返回方法A继续执行

事务隔离级别:在多线程或多并发情况下保证数据的完整性
脏读:A操作未提交,B读取到未提交的数据
幻读:(增加)
不可重复读:一个事务A中进行多次查询,其他事务B对数据进行了操作,导致事务A中读取的前后数据不一致(修改和删除)
-->isolation:事务隔离级别
1default:默认值,由底层数据库进行事务隔离级别判断
2、read_uncommitted:可以提交未提交数据,可以出现
3、read_committed:只能读取已提交事务的数据,解决脏读
4、pereatable_read:读取的数据被添加锁,防止其他事务修改数据,可以防止不可重复读、脏读
5、serializable:排队操作,对整个表加锁,一个事务在操作数据时,其他事务不能对事务进行操作
6、rollback-for:异常类型全限定名,出现什么异常回滚
7、no-rollback-for:出现什么异常的情况下不会滚

Spring常用注解
-->注解需要先进行扫描才能生效,IOC、DI、AOP、TX中都有专有注解
<!--注解扫描,扫描各类注解,其中IOC+DI注解直接生效,AOP和TX注解需要各自的驱动解析后才生效-->
<!--指定包下IOC+DI注解生效-->
<!--多个包扫描可以使用,分隔	包名/类名可以使用*代替如com.yjd.service.*-->
<context:component-scan base-package="com.yjd.service.impl">
	<!--type为类型:
	1、annotation:注解
	2、assignable:类
	expression:为注解全路径名-->
	<!--指定XXX注解不被扫描-->
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	<!--指定某个类的注解不被扫描-->
	<context:exclude-filter type="assignable" expression="com.yjd.service.impl.AccountServiceImpl"/>
	<!--指定XXX注解被扫描-->
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
	<!--指定某个类的注解被扫描-->
	<context:include-filter type="assignable" expression="com.yjd.service.impl.AccountServiceImpl"/>
</context:component-scan>

<!--AOP注解需要加载AspectJ驱动对注解进行解析-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<!--加载TX驱动解析事务注解-->
<tx:annotation-driven></tx:annotation-driven>

-->IOC
@Component:其他放置类的层
@Service("id"):service层,相当于配置了bean标签,ID默认为类名首字母小写
@controlor:-->servlet层
@repository:-->Dao-->DI
@Resource:先根据名称查找,再根据类型查找,找到已生成的对象注入到属性中(JDK官方提供)
@Autowired:根据类型进行查找,再根据名称进行查找再注入(Spring提供,建议使用),可以不写get/set方法
@Quaifier("别名"):Autowired联合使用,当有多个同一类型实例时,通过别名区别对象
@Value("${键}"):读取属性文件中的值,如:键=com.mysql.cj.jdbc.Driver

-->AOP
使用注解方式,通知执行顺序不同-->环绕前置、前置、环绕后置、后置
@Aspect:作用在通知类上生效
@Pointcut("execution(* com.yjd.test.*.*(..))"):指向切点方法,全路径,方法体不执行
@Before("aa()"):指向@Pointcut注解所在的方法,可以全路径,方法体在通知时执行
@After:同上
@Around:同上
@AfterThrowing:同上
 
-->目标类
@Component
public class MyTarget {

public void aa() {
  System.out.println("切点aa方法");
}
}

-->通知类
@Component
@Aspect
public class MyAdvice {

@Pointcut("execution(* com.yjd.test.*.*(..))")
public void aa() {
  System.out.println("指向切点方法,但不执行");
}

@Before("aa()")
public void bb() {

  System.out.println("指向@Pointcut注解指定的方法,相当于通知");

}
}

-->applicationContext.xml配置
<!--扫描包中注解-->
<context:component-scan base-package="com.yjd.test"></context:component-scan>
<!--AOP注解解析器-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

-->TX
1<!--注册事务注解解析驱动-->
<tx:annotation-driven></tx:annotation-driven>
2<!--Spring中事务的管理-->
<bean id="transactionManager" 		 		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"  ref="jdbc"></property>
</bean>
3@Transactional:为方法添加事务

-->Junit(方法)
@Test:单元测试
@Before:单元测试前执行
@After:单元测试后执行
//spring整合单元测试的注解
@ContextConfiguration(location={"classpath:ApplicationContext.xml"}):需要spring-test的jar包
@RunWith(Springjunit4ClassRunner.class)

SpringMVC

配置
-->对servlet进行封装,提供公共的servlet,可以根据请求动态调用处理方法
package com.yjd.controller;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author: Ada
 * @date: 2021/6/10 9:02
*/

//一个普通类充当前端控制器
@Controller
public class MyController {
 
 //配置处理器映射器映射路径
 @RequestMapping("/demo1")
 public String  demo1() {
 
     System.out.println("demo1");
     
     //直接请求转发方式跳转到对应String类型路径地址
     return "success.jsp";
     
 }
 
 @RequestMapping("/getParam1")
 public String  getParam1(HttpServletRequest req, HttpServletResponse resp) {
 
     req.getParameter("");
     
     return "success.jsp";
     
 }
 
 //通过表单name属性名获取对应的值
 @RequestMapping("/getParam2")
 public String getParam2(String uname,int age,String[] hobby1,String hobby2) {
 
     return "success.jsp";
 }
}

-->springMVC.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.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
    http://www.springframework.org/schema/tx
    https://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/mvc
    https://www.springframework.org/schema/mvc/spring-mvc.xsd">

 <context:component-scan base-package="com.yjd.controller"></context:component-scan>

 <!--加载映射器和适配器-->
 <mvc:annotation-driven></mvc:annotation-driven>

 <!--静态资源放行-->
 <!--mapping:url路径   location:本地路径-->
 <mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
 <mvc:resources mapping="/imgs/**" location="/imgs/"></mvc:resources>
 <mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
 <mvc:resources mapping="/static/**" location="/static/"></mvc:resources>

</beans>
     
-->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">
 <servlet>
     <servlet-name>mvc</servlet-name>
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:springMVC.xml</param-value>
     </init-param>
 </servlet>
 <servlet-mapping>
     <servlet-name>mvc</servlet-name>
     <!--除了jsp都进-->
     <url-pattern>/</url-pattern>
 </servlet-mapping>
</web-app>
静态资源放行
-->.jsp文件外,其他静态文件访问时直接放行,否则映射器无法匹配路径会报错,放行后直接找到磁盘中文件展示
<!--静态资源放行springmvc.xml中配置-->
<!--mapping:url路径   location:本地路径-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/imgs/**" location="/imgs/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>
springMVC执行流程
-->浏览器发送请求后由web.xml文件获取前端控制器(程序入口),并解析springMVC.xml文件
-->前端控制器将请求路径交由处理器映射器处理,找到匹配的映射方法
-->处理器映射器将方法信息反馈给前端控制器,前端控制器调用处理器适配器,将方法交由对应的处理器处理
-->处理器返回模型和视图,由处理器适配器返回给前端控制器
-->前端控制器调用视图解析器对模型和视图进行解析,并将解析结果返回给前端控制器
-->前端控制器调用视图,将视图结果进行渲染,并将渲染后视图返回给前端控制器
-->前端控制器将视图响应给浏览器进行展示
1、前端控制器DispatcherServlet:请求查询Handler、请求执行、请求解析视图、渲染视图、响应用户
2、处理器映射器HandlerMapping:返回处理器执行链
3、处理器适配器HandlerApadapter:根据方法的参数和返回值决定使用哪个处理器
4、处理器Handler:返回模型和视图ModleAndView
5、视图解析器Resolver:返回视图对象
6、视图View:渲染视图
-->三大组件:处理器映射器、处理器适配器、视图解析器        
image-20210610104136953
前台数据获取
-->参数注入方式
1、紧耦合方式:使用传统servlet方式
@RequestMapping("/getParam1")
public String  getParam1(HttpServletRequest req, HttpServletResponse resp) {
 req.getParameter("");
 
 return "success.jsp";
 
}

2、松耦合(解耦)方式:SpringMVC方式,方法参数值为前台表单name属性的值,数据类型可自动转换,400错误为前台参数错误
//通过表单name属性名获取对应的值
//checkbox类型的值可以使用String[] hobby/String hobby获取
@RequestMapping("/getParam2")
public String getParam2(String uname,String sex,String hobby,int password) {
 System.out.println(uname + sex + hobby + password);
 
 return "index.jsp";
}

3、形参为对象
//根据pojo中实体类的属性名自动注入数据,要求属性名与前台name属性值一致
@RequestMapping("/getParam3")
public String getParam3(Clazz clazz, Student student) {
 System.out.println(clazz);
 System.out.println(student);
 
 return "index.jsp";
}

<form action="getParam3" method="get">
 <p>
     班级ID:<input type="text" name="cid"/>
 </p>
 <p>
     班级名称:<input type="text" name="cname"/>
 </p>
 <p>
     学生ID:<input type="text" name="sid"/>
 </p>
 <p>
     学生姓名:<input type="text" name="sname"/>
 </p>
 <p>
     男:<input type="radio" name="sex" value="男"/>
     女:<input type="radio" name="sex" value="女"/>
 </p>
 <p>
     爱好:
     吃:<input type="checkbox" name="hobby" value="吃"/>
     喝:<input type="checkbox" name="hobby" value="喝"/>
     玩:<input type="checkbox" name="hobby" value="玩"/>
     乐:<input type="checkbox" name="hobby" value="乐"/>
 </p>
 <p>
     <input type="submit" value="提交"/>
 </p>
</form>
 
4、形参为对象,对象中有其他对象作为属性
//前台中name属性值为形参对象中的属性对象名.属性名
@RequestMapping("/getParam4")
public String getParam4(Clazz clazz) {
 System.out.println(clazz);
 return "index.jsp";
}

<form action="getParam3" method="get">
 <p>
     班级ID:<input type="text" name="cid"/>
 </p>
 <p>
     班级名称:<input type="text" name="cname"/>
 </p>
 <p>
     学生ID:<input type="text" name="student.sid"/>
 </p>
 <p>
     学生姓名:<input type="text" name="student.sname"/>
 </p>
 <p>
     男:<input type="radio" name="student.sex" value="男"/>
     女:<input type="radio" name="student.sex" value="女"/>
 </p>
 <p>
     爱好:
     吃:<input type="checkbox" name="student.hobby" value="吃"/>
     喝:<input type="checkbox" name="student.hobby" value="喝"/>
     玩:<input type="checkbox" name="student.hobby" value="玩"/>
     乐:<input type="checkbox" name="student.hobby" value="乐"/>
 </p>
 <p>
     <input type="submit" value="提交"/>
 </p>
</form>
 
5、形参为对象,对象中有List集合对象作为属性
@RequestMapping("/getParam5")
public String getParam5(Clazz clazz) {
 System.out.println(clazz);
 return "index.jsp";
}

<form action="getParam5" method="get">
 <p>
     班级ID:<input type="text" name="cid"/>
 </p>
 <p>
     班级名称:<input type="text" name="cname"/>
 </p>
 <p>
     学生ID:<input type="text" name="list[0].sid"/>
 </p>
 <p>
     学生姓名:<input type="text" name="list[0].sname"/>
 </p>
 <p>
     男:<input type="radio" name="list[0].sex" value="男"/>
     女:<input type="radio" name="list[0].sex" value="女"/>
 </p>
 <p>
     爱好:
     吃:<input type="checkbox" name="list[0].hobby" value="吃"/>
     喝:<input type="checkbox" name="list[0].hobby" value="喝"/>
     玩:<input type="checkbox" name="list[0].hobby" value="玩"/>
     乐:<input type="checkbox" name="list[0].hobby" value="乐"/>
 </p>
 <p>
     <input type="submit" value="提交"/>
 </p>
</form>
 
6、形参为对象,对象中有Map集合对象作为属性
@RequestMapping("/getParam6")
public String getParam5(Clazz clazz) {
 System.out.println(clazz);
 return "index.jsp";
}
<form action="getParam5" method="get">
 <p>
     班级ID:<input type="text" name="cid"/>
 </p>
 <p>
     班级名称:<input type="text" name="cname"/>
 </p>
 <p>
     学生ID:<input type="text" name="map[0].sid"/>
 </p>
 <p>
     学生姓名:<input type="text" name="map[0].sname"/>
 </p>
 <p>
     男:<input type="radio" name="map[0].sex" value="男"/>
     女:<input type="radio" name="map[0].sex" value="女"/>
 </p>
 <p>
     爱好:
     吃:<input type="checkbox" name="map[0].hobby" value="吃"/>
     喝:<input type="checkbox" name="map[0].hobby" value="喝"/>
     玩:<input type="checkbox" name="map[0].hobby" value="玩"/>
     乐:<input type="checkbox" name="map[0].hobby" value="乐"/>
 </p>
 <p>
     <input type="submit" value="提交"/>
 </p>
</form>
 
7、参数为日期类型/参数对象中有日期类型的属性
-->使用@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")注解,可以放在方法参数/类属性上
@RequestMapping("/getParam6")
public String getParam6(@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") Date date, Clazz clazz) {
 System.out.println(date);
 System.out.println(clazz);
 return "index.jsp";
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Clazz {
 
 private int cid;
 private String cname;
 @DateTimeFormat(pattern = "yyyy-MM-dd yy:mm:ss")
 private Date date;
 private Student student;
 private List<Student> list;
 private Map<String, Student> map;
 
}

<p>
 日学日期:<input type="text" name="date"/>
</p>

8、过滤器设置
<!--springMVC中filter过滤器设置在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>
</filter>
<filter-mapping>
 <filter-name>CharacterEncodingFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>
 
注解
@RequestMapping
-->可放在类和方法上,放在类上后,在方法中的路径为二级路径,注意相对路径的叠加问题
-->path/value为访问路径,可省略/
-->method限制请求方式
-->param限定前台的参数必须有name属性值为yang和sex属性值不限定
@RequestMapping(path="/路径",method=RequestMethod.POST,param={"name=yang","sex"})//注解@RequestMapping
@RequestMapping(value = "/getParam6",method = RequestMethod.POST,params = {"name=yang","sex"})
public String getParam6(@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") Date date, Clazz clazz) {
System.out.println(date);
System.out.println(clazz);
return "/index.jsp";
}

@PostMapping("/yjd/addOne"):只接受Post方式请求
@GetMapping("/yjd/addOne"):只接受Get方式请求

@RequestParam
-->只能放在参数上
-->value:前台数据name属性值,相当于起别名
-->required:true为必填项	false为非必填项
-->defaultValue:当前台传递数据未null时,可以使用默认值
@RequestParam(value = "前台name值",required = false,defaultValue = "默认值") String name

@PathVariable与restful方式联合使用
普通方式:http://localhost:8080/springmvc01/MyController/getParam5?cid=1&cname=s223&map%5B0%5D.sid=2&map%5B0%5D.sname=yang
restful方式:http://localhost:8080/springmvc01/MyController/getParam7/zs/li/ww
-->在方法参数中使用
@RequestMapping("/getParam6/{a}/{b}/{c}")
public String getParam7(@PathVariable String a, @PathVariable String b, @PathVariable String c) {
System.out.println(a);
System.out.println(b);
System.out.println(c);
return "/index.jsp";
}

@RequestHeader 获得请求头中信息
-->在方法参数中使用
@RequestMapping(value = "/getParam8")
public String getParam8(@RequestHeader("accept") String a) {
System.out.println(a);
return "/index.jsp";
}

@CookieValue:获取cookie中的信息
-->在方法参数中使用
@RequestMapping(value = "/getParam9")
public String getParam9(@CookieValue("JSESSIONID") String a) {
System.out.println(a);
return "/index.jsp";
}

@ResponseBody
-->可在类与方法中使用,代表使用ajax响应请求
@RequestMapping(value = "/yjd/respMethod6", produces = "application/json;charaset=GBK")
@ResponseBody
public Student respMethod6() {
Student student = new Student("杨", 20);
return student;
}

@JsonFormat(pattern = "yyyy-MM-dd")
-->ajax响应日期
@DateTimeFormat(pattern = "yyyy-MM-dd")
-->接收请求中日期数据
public class Student implements Serializable {

private String name;
private int age;
//响应时间格式化
@JsonFormat(pattern = "yyyy-MM-dd")
//请求接收时间格式化
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;

}
springMVC响应
-->单元方法使用void作为返回值时,在方法体内部必须进行响应
-->响应方式:
1、servletAPI方式
@RequestMapping("/yjd/respMethod2")
public void respMethod2(HttpServletRequest res, HttpServletResponse resp) throws IOException, ServletException {
 //请求转发
 res.getRequestDispatcher("/index.jsp").forward(res, resp);
 //重定向
 //resp.sendRedirect(res.getContextPath() + "/index.jsp");
 
}

2、springMVC方式
@RequestMapping("/yjd/respMethod1")
public String respMethod1() {
 //转发
 return "forward:/index.jsp";
 //重定向
 return "redirect:/index.jsp";
 
}

3View视图方式
@RequestMapping("/yjd/respMethod3")
public View respMethod3(HttpServletRequest res) {
 
 //请求转发
 //InternalResourceView internalResourceView = new InternalResourceView("/index.jsp");
 
 //重定向
 RedirectView redirectView = new RedirectView(res.getContextPath() + "/index.jsp");
 //return internalResourceView;
 return redirectView;
}

4ModelAndView方式
@RequestMapping("/yjd/respMethod4")
public ModelAndView respMethod4(HttpServletRequest res) {
 ModelAndView modelAndView = new ModelAndView();
 //以视图名称请求转发
 //modelAndView.setViewName("forward:/index.jsp");
 //以视图名称重定向
 //modelAndView.setViewName("redirect:/index.jsp");
 
 //以视图进行请求转发
 //modelAndView.setView(new InternalResourceView("/index.jsp"));
 //以视图进行重定向
 modelAndView.setView(new RedirectView(res.getContextPath() + "/index.jsp"));
 
 return modelAndView;
}

5、传统ajax方式,返回前台为String类型,需转Json,且编码格式需添加
@RequestMapping("/yjd/respMethod5")
public void respMethod5(HttpServletResponse resp) throws IOException {
 resp.setCharacterEncoding("utf-8");
 resp.setContentType("text/html;charaset=utf-8");
 
 Student student = new Student("杨", 20);
 resp.getWriter().print(new Gson().toJson(student));
 
}

$("#but1").click(function () {
 $.ajax({
     type: "post",
     url: "yjd/respMethod5",
     data: {},
     dataType: "json",
     success: function (result) {
         alert(result);
     },
     error: function () {
         alert("请求错误!")
     }
 });
});

6、springMVC的ajax方式,返回前台为Json,不需再转型,且编码格式不需添加,可通过context-Type查看类型
//可以选择设置编码
@RequestMapping(value = "/yjd/respMethod6", produces = "application/json;charaset=GBK")
@ResponseBody
public Student respMethod6() {
 Student student = new Student("杨", 20);
 return student;
}

7、ajax响应日期
@RequestMapping(value = "/yjd/respMethod6")
@ResponseBody
public Student respMethod6() {
 Student student = new Student();
 Date date = new Date();
 student.setBirth(date);
 
 return student;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {

 private String name;
 private int age;
 //响应时间格式化
 @JsonFormat(pattern = "yyyy-MM-dd")
 //请求接收时间格式化
 @DateTimeFormat(pattern = "yyyy-MM-dd")
 private Date birth;

}
SSM整合
-->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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.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
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--Spring配置jdbc-->
<bean id="jdbc" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysql_driver}">
</property>
<property name="url" value="${mysql_url}">
</property>
<property name="username" value="${mysql_username}">
</property>
<property name="password" value="${mysql_password}">
</property>
</bean>
<!--获得SqlSessionFactory工厂-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="jdbc">
</property>
<property name="typeAliasesPackage" value="com.yjd.pojo">
</property>
</bean>
<!--配置Mappers扫描-->
<bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="factory">
</property>
<property name="basePackage" value="com.yjd.mapper">
</property>
</bean>
<!--全部注解扫描,IOC+DI直接生效,AOP和TX需要驱动-->
<context:component-scan base-package="com.yjd.service.impl"></context:component-scan>
<!--配置事务管理对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="jdbc"></property>
</bean>
<!--加载TX驱动解析事务注解-->
<tx:annotation-driven></tx:annotation-driven>
<!--加载AOP注解解析驱动-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

-->springMVC.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.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
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--注解扫描,IOC+DI直接生效,AOP和TX需要驱动/驱动+管理对象-->
<context:component-scan base-package="com.yjd.controller"></context:component-scan>

<!--加载映射器和适配器-->
<mvc:annotation-driven></mvc:annotation-driven>

<!--静态资源放行-->
<!--mapping:url路径   location:本地路径-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/imgs/**" location="/imgs/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>

</beans>

-->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">

<!--解析ApplicationContext.xml文件-->
<context-param>
  <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>
<!--解析springMVC.xml文件-->
<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:springMVC.xml</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>DispatcherServlet</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-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>
</filter>
<filter-mapping>
  <filter-name>CharacterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

-->类实例与成员变量使用注解生成和注入
jar包
mybatis+spring+springMVC+lombok+jackson+jdbc共29

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x8o3IXpF-1654393801947)(C:\Users\纵横\AppData\Roaming\Typora\typora-user-images\image-20210611145239975.png)]

作用域
-->后台添加域中值
//请求域、会话域、全局域的使用方式与之前一致,注意形参与域对象的获取,前台使用EL/JSTL表达式接收
@RequestMapping("/yjd/scope")
public String scope1(HttpServletRequest res, HttpSession session) {
 //request域传值
 res.setAttribute("request", 1);
 //session域传值
 session.setAttribute("session", 2);
 //application域传值
 ServletContext application = res.getServletContext();
 application.setAttribute("application", 3);
 return "forward:/index.jsp";
}
//Model/ModelAndView作用域可以实现与servlet的解耦
//在请求转发响应时前台接收方式与请求域方式一致${requestscope.键}
//在重定向响应时域中设置的数据携带在url地址中,可以使用<%=request.getParamter("键")%>接收
@RequestMapping("/yjd/scope2")
public ModelAndView scope2(Model model) {
 model.addAttribute("model", 4);
 ModelAndView modelAndView = new ModelAndView();
 modelAndView.addObject("modelAndView", 5);
 modelAndView.setViewName("redirect:/index.jsp");
 return modelAndView;
}
-->前台接收域中值
<body>
<p>
 request:${requestScope.request}
</p>
<p>
 session:${sessionScope.session}
</p>
<p>
 application:${applicationScope.application}
</p>
<p>
 modelRequest:${requestScope.model}
</p>
<p>
 modelAndViewRequest:${requestScope.modelAndView}
</p>
<p>
 modelRedirect:<%=request.getParameter("model")%>
</p>
<p>
 modelAndViewRedirect:<%=request.getParameter("modelAndView")%>
</p>
</body>
视图解析器
-->为响应页面设置视图解析器
-->WEB-INF下页面为保证项目安全,不能直接访问,只能通过转发的方式跳转到指定页面进行访问
http://localhost:8080/springmvc03/WEB-INF/success.jsp-->需此路径才能访问
-->响应跳转时会经过视图解析器为路径增加前缀和后缀,组成完整跳转路径

<!--配置自定义视图解析器-->
<bean id="resolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>

-->控制单元
@RequestMapping("/{path}")
public String  respMethod7(@PathVariable String path) {
return path;
}

视图解析器下的路径查找顺序:
1/yjd/Login
2@RequestMapping("/yjd/Login")-->优先
3@RequestMapping("/{path}")
4、正常情况下走视图解析器加前后缀,如不想走需使用全路径(前端页面不在WEB-INF下的情况)
forward:/index.jsp
redirect:/index.jsp
@RequestMapping("/{path}")
public String  respMethod7(@PathVariable String path) {
return "forward:/save.jsp";
}
文件上传
-->success.jsp
<input type="file" id="file"/>
<input type="button" value="文件上传" id="but1"/>
 
$("#but1").click(function () {
 var file = $("#file")[0].files[0];
 var formData = new FormData();
 formData.append("f", file);
 $.ajax({
     type: "post",
     url: "yjd/upLoad",
     data: formData,
     processData:false,
     contentType:false,
     success: function (result) {
         alert(result);
     },
     error: function () {
         alert("请求错误!");
     }
 });
});

-->UpLoadController
1、文件存放在本地磁盘中
@RequestMapping("/yjd/upLoad")
@ResponseBody
public String upLoad(MultipartFile f, HttpServletRequest res, HttpServletResponse resp) throws IOException {
 String originalFilename = f.getOriginalFilename();
 File file1 = new File("E:/" + originalFilename);
 f.transferTo(file1);
 return "OK";
}

2、文件存放在本地服务器中
@RequestMapping("/yjd/upLoad")
@ResponseBody
public Map<String,String> upLoad(MultipartFile f, HttpServletRequest res) throws IOException {

//获得文件名称
String originalFilename = f.getOriginalFilename();
//获得文件类型
String contentType = f.getContentType();
//获得文件后缀
String substring = f.getOriginalFilename().substring(f.getOriginalFilename().lastIndexOf("."));
//获得请求所在服务器中文件存放地址
String realPath = res.getServletContext().getRealPath("/imgs");
//本地服务器中创建存放文件的文件夹
File file = new File(realPath);
if (!file.exists()) {
   file.mkdirs();
}
//创建随机文件名称,避免重名覆盖问题
String uuid = UUID.randomUUID().toString();
//组成文件新名称
String fileName = uuid + substring;
//将文件写入到指定目录中
f.transferTo(new File(file, fileName));
Map<String, String> map = new HashMap<>();
map.put("fileName", fileName);
map.put("contentType", contentType);
return map;
}

3、文件存放在远程服务器中
@RequestMapping(value = "/fileUplaod2",method = RequestMethod.POST)
@ResponseBody
public Map<String,String> fileUplaod2(MultipartFile  f, HttpServletRequest  request) throws IOException {

//5.创建 sun 公司提供的 jersey 包中的 Client 对象
Client client = Client.create();
//6.指定上传文件的地址,该地址是 web 路径
WebResource resource = client.resource("http://192.168.58.252:8888/imgs/"+f.getOriginalFilename());
//7.实现上传
String result = resource.put(String.class,f.getBytes());

Map<String,String>  map =new HashMap<>();
map.put("a",f.getOriginalFilename());
map.put("b",f.getContentType());

return map;

}

-->前台代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传页面</title>
<base href="<%=request.getContextPath()+"/"%>">
<script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript">

$(function () {

   $("#but1").click(function () {
       var file = $("#file")[0].files[0];
       var formData = new FormData();
       formData.append("f", file);
       $.ajax({
           type: "post",
           url: "yjd/upLoad",
           data: formData,
           //重要***
           processData:false,
           contentType:false,
           success: function (result) {
               alert(result);
               //本地服务器图片回显
               $("#sp1").html("<img src='http://localhost:8080/springmvc05/imgs/" + result.fileName + "' width='80px'/>");
               //远程服务器图片回显
               //$("#sp1").html("<img src='http://192.168.58.252:8888/imgs/"+result.a+"' width='80px'/>");

               $("#fileName").val(result.fileName);
               $("#contentType").val(result.contentType);
           },
           error: function () {
               alert("请求错误!");
           },
           //上传进度条
           xhr: function() {
               var xhr = new XMLHttpRequest();
               //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
               xhr.upload.addEventListener('progress', function (e) {
                   console.log(e);
                   //loaded代表上传了多少
                   //total代表总数为多少
                   var progressRate = (e.loaded / e.total) * 100 + '%';
                   //通过设置进度条的宽度达到效果
                   $('.progress > div').css('width', progressRate);
               })

               return xhr;
           }
       });
   });

});
</script>

<%--进度条样式--%>
<style type="text/css">
.progress {
   width: 600px;
   height: 10px;
   border: 1px solid #ccc;
   border-radius: 10px;
   margin: 10px 0px;
   overflow: hidden;
}
/* 初始状态设置进度条宽度为0px */
.progress > div {
   width: 0%;
   height: 100%;
   background-color: yellowgreen;
   transition: all .3s ease;
}
</style>
</head>
<body>
<form>
<h2>文件上传页面</h2>
<br/>
<%--获取文件--%>
<input type="file" id="file"/>
<%--上传文件--%>
<input type="button" value="文件上传" id="but1"/>
<span id="sp1"></span>
<p>
<%--进度条--%>
<div class="progress">
<div>

</div>
</div>
</p>
<p>
<%--获取上传文件新名称与文件类型--%>
<input type="text" id="fileName" name="fileName"/>
<input type="text" id="contentType" name="contentType"/>
<input type="button" value="提交" id="sub"/>
</p>
</form>
</body>
</html>

文件下载
-->前端
function getData(index, size) {
 var name = $("#name").val();
 $.ajax({
     type: "post",
     url: "yjd/findMore",
     data: {name: name,index:index, size: size},
     success: function (result) {
         totalPage = result.totalPageCount;
         current=result.index;
         $("#tb").empty();
         $.each(result.list, function (i, e) {
             $("#tb").append("<tr height=\"40px\">\n" +
                 "                <td>" + e.id + "</td>\n" +
                 "                <td>" + e.name + "</td>\n" +
                 "                <td>" + e.price + "</td>\n" +
                 "                <td>" + e.production + "</td>\n" +
                 "                <td>" + e.fileName + "</td>\n" +
                 "                <td>" + e.fileType + "</td>\n" +
                 "                <td><img src='http://localhost:8080/springmvc06/imgs/" + e.fileName + "' width='80px'/></td>" +
                 "                <td><a href='yjd/downLoad?fileName=" + e.fileName + "&fileType=" + e.fileType + "'>下载</a></td>" +
                 "            </tr>");
         });
         $("#anyOne").empty();
         $.each(result.numbers, function (i, e) {
             $("#anyOne").append("<a href=\"javascript:void(0)\" οnclick='getData(e,2)'>" + e + "&nbsp;&nbsp;&nbsp;</a>");
         });
     },
     error: function () {
         alert("请求失败!");
     }
 });

-->后端
@RequestMapping("/yjd/downLoad")
@ResponseBody
public void downLoad(String fileName, String fileType, HttpServletResponse resp) throws IOException {
 //设置下载到本地
 resp.setHeader("Content-Disposition", "attachment;Filename=" + fileName + "");
 resp.setContentType(fileType);
 //获取服务器端资源
 InputStream inputStream = new URL("http://localhost:8080/springmvc06/imgs/" + fileName).openStream();
 //响应下载文件
 ServletOutputStream outputStream = resp.getOutputStream();
 IOUtils.copy(inputStream, outputStream);
}
SpringMVC中拦截器
拦截器针对每一个控制单元(servlet)-->属于springMVC
拦截器每次请求会执行三个方法,可以获取xml配置中的bean

 执行顺序:preHandler(true-->控制单元-->postHandler(响应之前)-->afterCompletion(页面加载后)

 三个重写方法作用:
-->preHandler:编码设置、页面升级维护跳转、登录权限设置

-->postHandler:页面对比与升级改造、恶意字符替换
		       map充当作用域,前台使用requestscope接收

-->afterCompletion:资源关闭、垃圾清理

-->多层拦截器执行顺序:preHandler1-->preHandler2-->控制单元-->postHandler2-->postHandler1
  			        -->afterCompletion2-->afterCompletion1

-->springMVC配置
<mvc:interceptors>
<!--所有控制单元路径拦截-->
 <!--<bean class="com.yjd.controller.FlowerController"></bean>-->
 <!--指定路径拦截-->
 <mvc:interceptor>
     <!--拦截路径,前面必须有/-->
     <mvc:mapping path="/yjd/indexPage"/>
     <!--拦截器类全名-->
     <bean class="com.yjd.interceptor.MyInterceptor"></bean>
 </mvc:interceptor>
</mvc:interceptors>   

 -->控制层
@RequestMapping("/yjd/indexPage")
public String indexPage(Map<String,String> map) {
System.out.println("进入控制单元");
 map.put("msg", "枪支");
 return "forward:/index.jsp";
}

-->拦截器
package com.yjd.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @author: Ada
 * @date: 2021/6/16 10:50
*/
public class MyInterceptor implements HandlerInterceptor {

     @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
     System.out.println("preHandle");
     return true;
 }

 //非ajax请求时生效
 @Override
 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
     Map<String, Object> model = modelAndView.getModel();
     String msg = (String) model.get("msg");
     System.out.println(msg);
     if (msg.contains("枪支")) {
         String s = msg.replaceAll("枪支", "**");
         model.put("msg", s);
     }
     System.out.println("postHandle");

         }

     @Override
 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

         System.out.println("afterCompletion");
 }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值