> 文章列表 > Spring框架

Spring框架

Spring框架

Spring框架 

学什么:                 IOC(控制反转)                         DI(依赖注入)                AOP(面向切面编程){事物处理}

Spring是?  作用? 入门案例  注解开发

                  是:多个框架技术的统称,每个具体的技术都可以完成不同的功能

               作用:1.可以简化代码开发;

                          2.可以将代码中创建对象的行为进行控制反转,从而解决代码的耦合度

                          3.可以自动管理对象与对象之间的依赖关系;(对于对象来说,就是依赖注入)     

                         SpringFramework框架是:其他功能的基础;使用的回收需要导入Spring-context的坐标,并创建IOC容器; 

   核心容器IOC: 中文名叫控制反转,就是程序中所有创建对象的行为,不能再使用关键字new创建对象了,

                            统一交给Spring的ioc容器负责创建对象并保存对象,当我们的程序中需要使用到具体某个对象的时候,

                            直接ioc容器中获取对象即可;(ioc容器相当于是一个map集合)      

         入门案例: 1.导入Spring-context的坐标;

                            2.编写Spring的核心配置文件,并指定哪些类需要交给Spring管理;

                            3.编写测试的接口具体的实现类

                            4.编写测试类,从ioc容器中获取对象并使用; 

                             

                             

                                 

                                

                                 

四、 DI中文意思是:依赖注入,就是当某个对象的成员变量位置,需要其他的对象或数据的时候,可以让Spring自动的给

                                这个成员变量注入值;

                                如果是:简单类型,使用value

                                如果是:自定义引用数据类型,使用ref,ref的值是和Spring管理的某个bean的id一致;

                               

                                  

 有关配置文件的配置介绍:

                                        bean的name属性:可以给同一个对象,起多个名字,以便于通过多种方式获取该对象;

                                        bean的scope可以控制该对象是单列还是非单列的

                                                                scope="prototype"原型,非单利的,每创建一个对象开辟一个空间

                                                                scope="singleton"单列,spring默认的是单利的

                                 

                                         自动装配意思:告诉spring,某个中的成员变量,让spring自动把注入进去;

                                                                 代码实现:直接在bean的标签中添加一个:autowire="byType"属性即可;

                                                                                    要求被装配的bean必须唯一 !    

                   

                                  依赖自动装配特征:1.自动装配用于:引用类型依赖注入,不能对简单类型进行操作

                                                                  2.使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用

                                                                  3.使用按名称装配时(byName)必须保障容器中具有指定名称的bean,

                                                                     因变量名与配置耦合,不推荐使用

                                                                  4.自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

spring给成员变量注入集合和数组类型的数据:   

                                    

                                                       

                           框架整合:MyBatis Mybatis-plus  SpringMVC   .....            

 五、 第三方资源配置管理:             

                     管理第三方bean-Druid:1.导入Druid的连接池坐标;

                                                            2.在pring的核心配置文件中,配置bean;

                                                            3.给bean中的4个成员变量注入值;

                                                            4.在测试类中通过ioc容器获取bean对象即可;       

                                                                   

        1.管理DataSource连接池对象:

        2.加载properties属性文件【重点】 jdbc.properties:符号前面的吗名字相当于是map的key,可以自定义,符号后面的数据,是属于连接数据库时需要的信息,不能乱码 

                                          

                      【第二步】: 

               使用spring加载properties配置文件:1.在spring的核心配置文件中开启(context)命名空间  

                                                                         2.在核心配置文件中,指定properties文件的路径 

                                                                            

                                                                         3.在bean标签中,所有使用value注入值的地方,都可以通过${配置文件中的key}

                                                                            获取对应的值 

                                                                         4.获取ioc,测试 ;

                                                                        【第一步】编写jdbc.properties属性文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root

                                                                         小技巧:如果觉得上述复制粘贴方式不好改或者容易改错,其实idea是有提示功

                                                                                       能的,注意不要选错就行了。

                                                                                       有些版本的idea没有这个提示,那么就按照上面复制粘贴的方式改,

                                                                                       改完之后可以做成live template模板,后期直接用。

                                                                

                                                                      【第二步】在applicationContext.xml中开启开启context命名空间,

                                                                                        加载dbc.properties属性文件

                                                                      【第三步】在配置连接池Bean的地方使用EL表达式获取jdbc.properties属性文件

                                                                                        中的值

                                        

<bean class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/>
</bean>

                                                                        注意事项:配置不加载系统属性

                                                                                         问题:如果属性问价你中配置的不是jdbc.username,

                                                                                                    而是username=root666,那么使用${username}获取到的

                                                                                                    不是root66,而是计算机的名称。

                                                                                         原因:系统属性的优先级比我们属性文件中的高,

                                                                                                    替换了我们的username=root666。

                                                                                         解决1:换一个名称 ,例如不叫username,叫jdbc.username。

                                                                                         解决2:使用system-properties-mode="NEVER"属性表示不使用系统属性

 

                                 加载 properties文件写法标准格式:<context:property-placeholder location="classpath:*.properties"/>

 spring半注解开发:1.在核心配置文件中,开启注解扫描的功能 

                                

                                2.在指定的包的类中添加注解:@Controller   @service  @Repository

                                   

                                3.如果涉及到简单类型的数据,可以直接使用@Value("注入的值")

                                   

                                4.如果涉及到引用数据类型的数据,可以直接使用@Autowired按类型自动注入;

     spring提供的component三个衍生注解:

                                                               @Component:用于表现层bean定义

                                                                @service:用于业务层bean定义

                                                                @Repository:用于数据层bean定义

                                                                 

 spring的纯注解开发:

                                不需要编写spring的核心配置文件, 直接通过一个配置类,替代核心配置文件文件即可;

                                1.自定义一个核心配置类,替代核心配置文件;

                                2.在指定的包中定义的类的上面添加指定的注解

                                3.在测试类中获取ioc容器的时候,使用的是AnnotationConfigApplicationContext即可;

 

     注解管理单列@Scope("prototype")

                                

      生命周期     :                
 @PostConstruct  创建对象的时候,会执行带有这个注解的方法
@PreDestroy       销毁对象的时候,会执行带有这个注解的方法   

 指定类型或指定名称

注解加载properties配置文件和依赖注入

简单类型使用  @Value(数据值)   @Value(${配置文件中的key})
自定义类型    @Autowired   如果类型不唯一,可以指定按名称装配   @Qualifier("abc")// 明确的指定按名称注入,这里面的名称必须和dao中配置的名称一致
在配置类的上面通过@PropertySource({"classpath:jdbc.properties"})可以加载配置文件

Spring整合junit:

                                       好处:使用spring整合junit之后,我们无需自己创建ioc容器对象了,可以直接在测试中注入业务层对象,

                                                  从而在测试方法中使用注入的对象直接调用方法,简化spring操作 

                                        步骤:1.导入两个坐标;

                                                   2.在测试类的上面添加两个注解

                                                        @RunWith(SpringJUnit4ClassRunner.class) :告诉spring这个测试类希望spring管理

                                                        @ContextConfiguration:告诉spring核心配置类是谁

                                                   3.在测试中注入业务层对象:直接设计成员变量,使用@Autowired注解即可;

                                                   4. 在测试方法中直接使用业务层对象调用方法即可;@Test:测试业务层方法的代码

                             

                                    dao数据层业务层搭建及配置文件

                                    

                                       注意事项:junit的依赖至少要是4.12版本,可以是4.13等版本,否则出现如下异常:                                                                                          

Spring整合mybatis:       

                                             好处:所有有关联mybatis的代码,包括事务管理,都可以让spring处理,简化mybatis代码     

                                            步骤 :1.导入坐标;

                                                        2.写配置类,在类中定义两个方法,

                                                                             分别返回:SqlSessionFactoryBean,MapperScannerConfigurer         

                                                        3.在测试类中测试即可; 

                                                 

                                                简单的javabean-->dao层数据层接口-->service业务层接口和业务层实现类

                                                                                                测试类注入:核心配置类,然后核心配置类注入:配置文件、扫描包、找代码

                                                 

                                               流程分析示意图:

          

 代码:spring整合mybatis创建带驼峰和分页的bean

//spring整合mybatis的类
public class MyBatisConfig {private String javaBeanPackage="com.sprpro.demo02_Anno_MyBatis.pojo";private String mapperPackage="com.sprpro.demo02_Anno_MyBatis.dao";//自定义一个方法,返回mybatis的核心对象交给ioc容器即可整合成功@Beanpublic SqlSessionFactoryBean mybatis(DataSource ds){// 1: 创建用于创建SqlSessionFactory的对象SqlSessionFactoryBeanSqlSessionFactoryBean bean = new SqlSessionFactoryBean();// 2: 给SqlSessionFactoryBean 设置数据源;称连接池bean.setDataSource(ds);//DataSource:数据源// 3: 给SqlSessionFactoryBean 设置扫描javabean所在的包:称别名bean.setTypeAliasesPackage(javaBeanPackage);// 4: 给SqlSessionFactoryBean 设置其他插件,例如: 分页插件,驼峰命名等// 4.1: 驼峰命名Configuration con = new Configuration();con.setMapUnderscoreToCamelCase(true);bean.setConfiguration(con);// 4.2: 分页插件// 4.2.1: 准备插件需要的参数Properties p = new Properties();// 4.2.2: 开启分页插件的固定写法p.setProperty("value","true");// 4.2.3: 创建分页插件对象PageInterceptor page = new PageInterceptor();// 4.2.4: 给分页插件设置参数page.setProperties(p);// 4.2.5 : 将分页插件交给SqlSessionFactoryBean管理bean.setPlugins(new Interceptor[]{page});// 5: 返回准备好的SqlSessionFactoryBean,spring的ioc管理 SqlSessionFactoryBean的时候,会自动从SqlSessionFactoryBean中获取SqlSessionFactoryreturn bean;}// 专门处理扫描mybatis的接口映射的对象@Beanpublic MapperScannerConfigurer mapper(){//1:创建阿里的druid连接池信息MapperScannerConfigurer mapper = new MapperScannerConfigurer();// 2: 设置扫描的接口包mapper.setBasePackage(mapperPackage);return mapper;}
}

 AOP:

                OOP强调是所有的事情都让对象去做,而AOP强调的是我可以拿刀把原来的代码切开,在切开刀刃里面加一些东西

 

                     是:一种面向切面编程的思想;用于做升级可以用

                 作用:可以在已经写好的功能的基础上,不改变原有代码的前提下,利用动态代理的技术对原有功能进行增强;

                 术语:1.连接点:接口中的任意一个方法,都可以叫连接点;例如:update()、delete()、select()等都是连接点

                            2.切入点:进行功能增强了的方法,例如:update()、delete()、select()方法没有被增强所以不是切入点,

                                             但是是连接点。切入点也可以叫做切点;

                                             在SpringAOP中:一个切入点可以只描述一个具体方法,也可以匹配多个方法

                                                                        一个具体方法:com...dao包下的BookDao接口中的无形参无返回值的save方法

                                                                        匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接

                                                                                                 口中的任意方法,所有带有一个参数的方法

                            3.通知:在切入点前后执行的操作,也就是增强的共享功能

                                          在SpringAOP中,功能最终以方法的形式呈现

                            4.通知类:通知方法所在的类叫做通知类

                            5.切面:描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。

                            6.织入:把通知添加到切入点(切点)的行为,叫做织入;

                              切入点(Pointcut)              通知(Advice)            切面(Aspect)

        代码步骤:  1.导入坐标

                            2.编写通知类

                            3.在通知类中编写切点通知切面

                            4.测试类测试即可  

 例如代码如下:

       准备工作        

/*这是一个通知类,需要让spring管理*/
@Component
@Aspect// 告诉spring,这是一个通知类
public class MyAd {// 通知类// 描述切点  格式: 方法是什么样的返回值  哪个包哪个类哪个方法带什么参数@Pointcut("execution(* com...demo03_Anno_AOP.service.AccountService.selectAll())")public void qieDian(){}// 写一个具体的增强的内容,(通知)@Before("qieDian()")  // 切面,让我们自定义的myZQ方法和上面定义的切点产生绑定,这个关系就是切面public Object myZQ(){System.out.println("我要增强了:"+System.currentTimeMillis());return null;//currentTimeMillis获取的时间}
}

 AOP注解:@EnableAspectJAutoProxy:开启AOP注解功能  @Aspect:通知类注解  @Pointcut:切入点注解

                   @Before:自定义切面注解;执行之前先要干的事情

                   @Around表示,同时方法带有一个形参: ProceedingJoinPoint

                 AOP环绕通知:

                                           使用:@Around表示,同时方法带有一个形参:ProceedingJoinPoint

                                                     可以通过ProceedingJoinPoint对象的getArgs方法,获取原始方法的实际参数,从而对原始方                                                           法的进行修改  

                                                     可以通过ProceedingJoinPoint对象的proceed方法,让原始方法真正的执行起来;从而控制原                                                           始方法的执行时机

                                                     可以通过...对象的proceed方法返回值,对返回值做任意的修改,从而控制原始方法的返回结果

                                                     最终达到的效果就是环绕通知可以控制原始方法参数返回值,异常,执行时机等;

                                     参考代码:   返回值类型:*、包名:com..、类名:*service+、方法名:*、参数..

                                                         

//这是一个通知类,需要让spring管理
@Component
@Aspect
public class MyAd {// 通知类// 描述切点  格式: 方法是什么样的返回值  哪个包哪个类哪个方法带什么参数//@Pointcut("execution(* com.sprpro.demo03_Anno_AOP.service.AccountService.selectAll())")// * 表示返回值类型是任意的// com..   com包下的任意层// *Service+  表示类名以任意单词开头,中间必须包含service,后面必须还有1至多个字符// *(..)   表示任意方法名和任意参数个数和类型@Pointcut("execution(* com..*Service+.*(..))")public void qieDian(){}// 写一个具体的增强的内容,(通知)@Around("qieDian()")  // 切面,让我们自定义的myZQ方法和上面定义的切点产生绑定,这个关系就是切面public Object myZQ(ProceedingJoinPoint pjp) throws Throwable {System.out.println("我要增强了:"+System.currentTimeMillis());// 1: 通过pjp获取要增强的方法的原始参数Object[] args = pjp.getArgs();// 2: 对参数的类型进行判断,如果是Account类型,就将里面的名称和金额进行修改if (args!=null){for (int i = 0; i < args.length; i++) {// 判断数组中的每一个元素是不是Account类型if(args[i] instanceof Account){System.out.println("参数增强了....");Account a = (Account) args[i];a.setName(a.getName()+"嘿嘿");a.setMoney(a.getMoney()*10);args[i] = a;}}}Object proceed = null;try {// 3: 让原始方法执行proceed = pjp.proceed(args);if(proceed!=null){if(proceed instanceof Account){System.out.println("对返回值增强了....");Account a = (Account) proceed;a.setName(a.getName()+"嘿嘿结果");a.setMoney(a.getMoney()/100);}}} catch (Throwable e) {e.printStackTrace();System.out.println("原始方法出异常了,在这里补救....");}return proceed;}
}

案例:

           需求:在不改变原始service和dao代码的情况下,完成对业务层方法执行一万次的用时统计;

           分析:可以使用aop思想,利用环绕通知,循环调用方法1万次,且方法执行前后,分别记录系统时间,用时间差就可以算出程序的万次执行效率了;

//这是一个通知类,需要让spring管理
@Component
@Aspect
public class MyAd {// 通知类//切点表达式,用于描述什么样的方法,可以成为切点@Pointcut("execution(* com..*Service+.*(..))")public void qieDian(){}// 写一个具体的增强的内容,(通知)@Around("qieDian()")  // 切面,让我们自定义的myZQ方法和上面定义的切点产生绑定,这个关系就是切面public Object myZQ(ProceedingJoinPoint pjp) throws Throwable {System.out.println("我要增强了:"+System.currentTimeMillis());// 1: 通过pjp获取要增强的方法的原始参数Object[] args = pjp.getArgs();// 2:不修改参数//获取原始方法的签名,通过签名获取正在执行的类和方法//获取执行的签名对象Signature signature = pjp.getSignature();//获取接口/类全限定名String className = signature.getDeclaringTypeName();//获取方法名String methodName = signature.getName();long t1 = System.currentTimeMillis();Object proceed = null;for (int i = 0; i < 10000; i++) {proceed = pjp.proceed(args);}long t2 = System.currentTimeMillis();// 3:在方法执行之前,记录当前系统时间,在方法执行之后,再次记录时间,两个时间差就是方法运行的时间//4:不修改返回值,直接返回方法执行的结束//System.out.println("执行一万次用时:"+(t2-t1)+"毫秒");System.out.println("执行"+className+"中的"+methodName+"一万次用时:"+(t2-t1)+"毫秒");return proceed;}
}

Spring事务:

                               是:认为规定的一组操作,这组操作中可以包含多个动作,这些动作应该保证要么全部成功,要么全部失败,

                                      事务就是专门做这个事情的;  

                               相关类和接口:

                                                        Spring管理事务使用的是:PlatformTransactionManager接口;

                                                        而mybatis管理事务使用的是:DataSourceTransactionManager类;

                            事务管理的思路:

                                                        由于DataSourceTransactionManager类已经实现了PlatFormTransactionManager接口,

                                                        所以我们只需要将DataSourceTransactionManager以第三方bean的形式交给ioc容器管理,

                                                        再配合spring事务相关的注解即可完成事物的控制了;

                               代码实现步骤:

                                                        1.自定义一个专门加载DataSourceTransactionManager对象的配置类,并在核心配置类上

                                                           导入该配置类;

                                                        2.在核心配置列的上面使用@EnableTransactionManagement开启事务支持;

                                                        (代码参考上面的MySpringConfig)

                                                        3.在业务层接口中,想要开启事务的方法上面添加@Transactional注解即可;

                                                        (方法出运行时异常会自动回滚,不出异常会自动提交)

转账案例:价钱和减钱

                1.config包里配置创建个(加载对象的配置类)

//2.注入平台事务管理器  固定
//专门处理mybatis的事务交给ioc容器的配置类
public class ShiWuConfig {@Bean//Spring管理事务使用的是:PlatformTransactionManager接口;public PlatformTransactionManager shiWu(DataSource ds){//1:创建mybatis的事务管理器对象DataSourceTransactionManager manager = new DataSourceTransactionManager();//2:给事务管理器设置一个连接池manager.setDataSource(ds);//3:返回事务管理器return manager;}
}

                  2.在核心配置列的上面使用@EnableTransactionManagement开启事务支持;

@Configuration
@ComponentScan("com.sprpro.demo06_Anno_ShiWu")
@PropertySource({"classpath:jdbc.properties"})
@Import({DruidConfig.class, MyBatisConfig.class, ShiWuConfig.class})
//@EnableAspectJAutoProxy//开启AOP注解功能
@EnableTransactionManagement//开启事务
public class MySpringConfig {
}

                 dao层接口层:

public interface AccountMapper {@Select("Select * FROM tbl_account")List<Account> selectAll();@Insert("insert into tbl_account values (null,#{name},#{money})")void insertAccount(Account a);@Select("select * from tbl_account where id=#{id}")Account selectById(Integer id);@Update("UPDATE tbl_account SET money=money+#{money} WHERE name = #{name}")void inMoney(@Param("name") String name, @Param("money") Double money);@Update("UPDATE tbl_account SET money=money-#{money} WHERE name = #{name}")void outMoney(@Param("name") String name, @Param("money") Double money);
}

service层:业接口务层

3.在业务层接口中,想要开启事务的方法上面添加@Transactional注解即可;

                                                        (方法出运行时异常会自动回滚,不出异常会自动提交)

public interface AccountService {// 该接口中包含了两个连接点List<Account> selectAll();// 由于该方法符合切点表达式的描述,所以该方法就是切点void insertAccount(Account a);// 该方法只是一个普通的连接点而已Account selectById(Integer id);//转账的方法@Transactionalvoid trans(String inname,String outname,Double money);
}

service层:业务实现类层

// 要加注解,让spring直接管理
@Service
public class AccountServiceImpl implements AccountService {//设计一个dao的对象@Autowiredprivate AccountMapper dao;@Overridepublic List<Account> selectAll() {return dao.selectAll();}@Overridepublic void insertAccount(Account a) {dao.insertAccount(a);}@Overridepublic Account selectById(Integer id) {return dao.selectById(id);}@Overridepublic void trans(String inname, String outname, Double money) {//调用dao的加钱和减钱的方法即可完成转账的行为dao.inMoney(inname,money);//加钱dao.outMoney(outname,money);//减钱}
}

 测试类:

@RunWith(SpringJUnit4ClassRunner.class)
// 告诉spring我们的核心配置类是谁
@ContextConfiguration(classes = MySpringConfig.class)
public class MyAOPTest {@Autowiredprivate AccountService as;@Testpublic void testAopSeleactAll(){//转账as.trans("tom","jerry",100.0);List<Account> list = as.selectAll();System.out.println(list);}
}

 配置:

 实现:

                                        事务案例:

                                                        需求:无论转账的行为是否成功,都要记录转账日志;

                                                        分析:由于转账的业务层已经开启了一个事务,所以必须让日志的业务层在额外开启一个

                                                                   新的日志即可实现效果;

//创建数据库
USE spring_db;
CREATE TABLE tbl_log(id INT PRIMARY KEY AUTO_INCREMENT,info VARCHAR(255),createDate DATE
);
/*专门操作日志的dao接口*/
public interface LogMapper {@Insert("insert into tbl_log values (null,CONCAT(#{outname},'给',#{inname},'转了',#{money}),now())")void insertLog(@Param("inname") String iname, @Param("outname")String outname, @Param("money")Double money);
}
//业务层接口
public interface LogService {//给他单独加一个事务,告诉spring,不管调用我这个方法的其他类有没有事务,我自己都要开启一个新的事务@Transactional(propagation = Propagation.REQUIRES_NEW)void insertLog(String iname, String outname, Double money);
}

//业务层实现类
@Service
public class LogServiceImpl implements LogService {@Autowiredprivate LogMapper dao;@Overridepublic void insertLog(String iname, String outname, Double money) {dao.insertLog(iname,outname,money);}
}
//业务层实现类
// 要加注解,让spring直接管理
@Service
public class AccountServiceImpl implements AccountService {//设计一个dao的对象@Autowiredprivate AccountMapper dao;//日志    @Autowiredprivate LogService log;@Overridepublic List<Account> selectAll() {return dao.selectAll();}@Overridepublic void insertAccount(Account a) {dao.insertAccount(a);}@Overridepublic Account selectById(Integer id) {return dao.selectById(id);}@Overridepublic void trans(String inname, String outname, Double money) {try {//调用dao的加钱和减钱的方法即可完成转账的行为dao.inMoney(inname, money);//加钱int i=1/0;//转账失败  注释了则转账成功日志库记录dao.outMoney(outname, money);//减钱} finally {System.out.println("fnally执行了.....");log.insertLog(inname,outname,money);只要我不出异常,都会执行,记录日志库}}
}

//测试类
@RunWith(SpringJUnit4ClassRunner.class)
// 告诉spring我们的核心配置类是谁
@ContextConfiguration(classes = MySpringConfig.class)
public class MyAOPTest {@Autowiredprivate AccountService as;@Testpublic void testAopSeleactAll(){//转账as.trans("tom","jerry",100.0);List<Account> list = as.selectAll();System.out.println(list);}
}

SpringMVC:

                              是:spring家族提供的一个封装了servlet的框架,是基于java实现MVC模型轻量级Web框架

                                     SpringMVC就是对servlet的一个封装!

                          作用:1.可以简化servlet的开发,便捷的对浏览器做请求和响应处理;

                                     2.比servlet灵活性更强,代码开发更方便;

                          优点:1.使用简单,开发便捷(相比于servlet)2.灵活性强    

                          步骤:1.创建web工程(Mave架构) 

                                     2.设置tomcat服务武器,加载web工程(tomcat插件 )

                                     3.导入坐标(SpringMVC+Servlet)

                                     4.定义处理请求的功能类(UserController)

                                     5.编写SpringMVC配置类,加载处理请求的Bean

                                     6.加载SpringMVC配置,并设置SpringMVC请求拦截的路径

                                        

                                      

                                                                                                                    注意:对于SpringMVC而言,Controller方法返回值默认表示要跳转的页面,没有对应的页面就会报错

                                                如果不想跳转页面而是响应数据,那么久需要在方法上使用@ResponseBody注解        

                                                @Controller:SpringMVC控制器类定义上方

                                                @RequestMapping:设置当前控制器方法请求访问路径

                                                @ResponseBody:设置当前控制器方法响应内容为当前返回值,无需解析

                                                                                 让返回值作为响应体,而不是跳转的资源

                                        

  

                                                                     

                                                                               合并成一个容器,遇到service,controller,dao等都往spring容器里加

                           AbstractDispatcherServletInitializer:这个类当底层的DispatherServlet初始化后会执行这个类中的逻辑

                                                                                     1.告诉框架web层的类在哪一个包中存在 

                                                                                          

                                                                                     2.设定SpringMVC控制的范围

                                                                                     

                                                                                     3.加载非SpringMVC的bean

                                                                                      

                                                                                     AbstractAnnotationConfigDispatcherServletInitializer(简化书写):

                                                                                    

                                                                 

 POSTMan:

                是:一款软件,可以帮助我们给服务器发送各种格式的请求,并获取响应;

             使用:无需安装,双击即可使用,第一次使用需要注册账号;

                     1.创建workspace;(工作空间)                                                            

                     2.在workspace下面创建connections(文件夹)

                     3.在connection下面创建多个连接并存储,以便于下一次直接发送请求

简单参数处理: 

                        概述:Springmvc可以帮助我们处理浏览器请求是携带的参数,我们只需要在controller的方法中

                                   设计与浏览器对应的参数名的形式参数即可接收到浏览器的参数了

                                  参数为普通参数:当参数名和变量名不同,使用@ReaquestParam绑定参数关系 

                                                                

                                        get请求中文参数:

                                                                    

                                        post请求中文参数: 

                                                                         

                                                                    

                                        参数为POJO:请求参数名形参对象属性名相同,定义POJO类型形参既可以接收参数

                                                                 注意强调:请求参数key的名称要和POJO中属性的名称一致,否则无法封装                                                                                       

                                                                         

                             嵌套POJO类型参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性次数

                                   参数为数组类型:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型即可接收参数

                                       集合类型参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系                                   @RequestParam和@RequestBody的区别:

                                                        @RequestParam用于接收url地址参数,表单传参【application/x-www-from-urlencoded】

                                                        @RequestBody用于接收json数据【application/json】   

json参数的获取:

                            1.导入坐标

                            2.设置发送json数据(请求boby中天机json数据)

                            3.开启json自动解析支持:@ableWebMvc 

                            4.在方法的形参前面添加注解      

//1.导入坐标<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency>

                    @RequestBody:将请求中请求体所包含的数据传递给请求参数, 此注解:一个处理器方法只能使用一 次   

                                       注意:json一般是在请求体中携带,所有这里需要使用@RequestBody转成参数需要的                 

//4.在方法的形参前面添加注解  // 获取请求体中的数组参数@RequestMapping("/listJson")//这个就是一个普通的数组不是json数组public String listParamForJson(@RequestBody List<String> likes){System.out.println("list common(json)参数传递 list ==> "+likes);return "{'module':'list common for json param'}";}//注意json一般是在请求体中携带,所有这里需要使用@RequestBody转成参数需要的

 

//5种简单参数获取方式
//- 普通参数
//- POJO类型参数
//- 嵌套POJO类型参数
//- 数组类型参数
//- 集合类型参数
// 获取get请求的普通参数@RequestMapping("/get")public String getParam(String name,int age){System.out.println("getParam方法获取的name="+name);System.out.println("getParam方法获取的age="+age);return name+"====>"+age;}// 获取javabean请求的参数@RequestMapping("/javabean")public String javabeanParam(Student stu){System.out.println(stu);return "ok";}// 获取数组参数@RequestMapping("/array")public String arrayParam(String[] likes){System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));return "ok";}// 获取集合参数   @RequestParam 专门针对集合类型的参数做了一个标记@RequestMapping("/list")public String listParam(@RequestParam List<String> likes){System.out.println("集合参数传递 likes ==> "+ likes);return "{'module':'list param'}";}

                               json参数的形式:

                                                         1.普通数组[元素1,元素2....]

                                                         2.json对象{key1:value,key2:value2...}

                                                         3.json数组[{key1:value1,key2:value2...},{key1:value1,key2:value2...}]           

日期参数处理:默认支持用 / 连接日期信息,如果需要自己指定格式,可以使用@DataTimeFormat注解指定格式即可

 // 获取请求体中的json形式的javabean数组@RequestMapping("/date")public String date(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date,// M d 表示月份的数值跟着实际情况走,MM  dd表示实际月份不够两位的时候,必须使用0补够两位@DateTimeFormat(pattern = "yy年M月d日") Date date1,Date date2){System.out.println(date);System.out.println(date1);System.out.println(date2);return "中文测试";}

响应json数据:

                                      

                    只要开启:@EnableWebMvc在方法中直接返回对象或集合,springMvc就可以把对象或集合转成json格式的数据       

                                        开启springMvc多项辅助功能,其中一个是开启json和java对象互转的开关         

 // 响应学生对象,springmvc会自动将学生对象转成json形式;@RequestMapping("/toStu")public Student toStudentJson(){Student student = new Student(12,"张三",22);student.setAddr(new Address("s678","119期"));return student;}// 响应学生对象,springmvc会自动将学生对象转成json形式;@RequestMapping("/toListStu")public List<Student> toStudentListJson(){List<Student> list = new ArrayList<>();Student student = new Student(12,"张三",22);student.setAddr(new Address("s678","119期"));list.add(student);Student student2 = new Student(22,"张三22",22);student2.setAddr(new Address("s122678","119期22"));list.add(student2);return list;}

Rest风格:

                        

Rest风格综合案例:

创建数据库表:

-- 创建ssm_db数据库
CREATE DATABASE IF NOT EXISTS ssm_db CHARACTER SET utf8;-- 使用ssm_db数据库
USE ssm_db;-- 创建tbl_book表
CREATE TABLE tbl_book(id INT PRIMARY KEY AUTO_INCREMENT, -- 图书编号TYPE VARCHAR(100), -- 图书类型NAME VARCHAR(100), -- 图书名称description VARCHAR(100) -- 图书描述
);
-- 添加初始化数据
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring实战 第5版','Spring入门经典教材,深入理解Spring原理技术内幕');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5核心原理与30个类手写实战','十年沉淀之作,手写Spring精华思想');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5设计模式','深入Spring源码剖析,Spring源码蕴含的10大设计模式');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播就该这么做:主播高效沟通实战指南','李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播销讲实战一本通','和秋叶一起学系列网络营销书籍');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播带货:淘宝、天猫直播从新手到高手','一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');

pojo层:javaBean-简单的

@Data
@NoArgsConstructor
@AllArgsConstructor
//POJO实体类
public class Book {private Integer id;private String type;private String name;private String description;//同学们自己重写getter、setter、toString()方法...
}

    dao层 :-数据层                      

//  dao层 -数据层
public interface BookMapper {//专门操作数据库的接口层 dao@Select("SELECT * FROM tbl_book")List<Book> selectAll();@Select("SELECT * FROM tbl_book WHERE NAME Like CONCAT('%',#{name},'%')")List<Book> selectByLikeName(String name);@Insert("INSERT INTO tbl_book VALUES (null,#{type},#{name},#{description})")int insertBook(Book book);@Delete("DELETE FROM tbl_book WHERE id=#{id}")int delById(Integer id);@Update("update tbl_book set type = #{type},name=#{name},description=#{description}  where id=#{id}")int updateById(Book book);
}

service层:接口业务层

public interface BookService {List<Book> selectAll();List<Book> selectByLikeName(String name);int insertBook(Book book);int delById(Integer id);int updateById(Book book);
}

 service层:业务实现类层

@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookMapper dao;@Overridepublic List<Book> selectAll() {return dao.selectAll();}@Overridepublic List<Book> selectByLikeName(String name) {return dao.selectByLikeName(name);}@Overridepublic int insertBook(Book book) {return dao.insertBook(book);}@Overridepublic int delById(Integer id) {return dao.delById(id);}@Overridepublic int updateById(Book book) {return dao.updateById(book);}
}

springMVC轻量级Web层框架,对servlet的一个封装;参 调 响 不用再写servlet。+rest风格请求方式及简化参数的获取和代码操作

//controller层
@RestController
@RequestMapping(value = "/book", produces = "application/json;charset=utf-8")
public class BookController {@Autowiredprivate BookService bs;@GetMappingpublic List<Book> selectAll() {return bs.selectAll();}@GetMapping("/{name}")public List<Book> selectByLikeName(String name) {return bs.selectByLikeName(name);}@PostMappingpublic int insertBook(@RequestBody Book book) {return bs.insertBook(book);}@DeleteMapping("/{id}")public int delById(Integer id) {return bs.delById(id);}@PutMappingpublic int updateById(Book book) {return bs.updateById(book);}
}

接下来是进行配置

resources:jdbc.properties配置 使用纯注解对mybatis封装

0.创建工程添加依赖和插件

1.sring整合Mybatis:数据连接 JDBC数据属性的注入

配置JDBC
abc=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ssm_db?useSSL=false&useUnicode=true&characterEn=utf-8
jdbc.username=root
jdbc.password=....//对应配置文件下的如下:
//数据连接的配置类public class DruidConfig {// 定义4个成员变量,利用@value注入properties中的信息,以共 pool方法使用@Value("${abc}")private String dc;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String un;@Value("${jdbc.password}")private String pw;// 自定义一个方法,生成一个连接池信息,交给ioc容器@Beanpublic DataSource pool(){// 1: 创建阿里的druid连接池信息DruidDataSource ds = new DruidDataSource();// 2: 将成员变量的4个信息保存到ds中ds.setDriverClassName(dc);ds.setUrl(url);ds.setUsername(un);ds.setPassword(pw);return ds;}
}

2.固定不变的MyBatisConfig的类:

public class MyBatisConfig {private String javaBeanPackage="com.spmvc.demo01_BookSystem.pojo";//填写自已对应的javabean包名private String mapperPackage="com.spmvc.demo01_BookSystem.dao";//填写自已对应的数据包名@Beanpublic SqlSessionFactoryBean mybatis(DataSource ds){// 1: 创建用于创建SqlSessionFactory的对象SqlSessionFactoryBeanSqlSessionFactoryBean bean = new SqlSessionFactoryBean();// 2: 给SqlSessionFactoryBean 设置数据源bean.setDataSource(ds);// 3: 给SqlSessionFactoryBean 设置扫描javabean所在的包bean.setTypeAliasesPackage(javaBeanPackage);// 4: 给SqlSessionFactoryBean 设置其他插件,例如: 分页插件,驼峰命名等// 4.1: 驼峰命名Configuration con = new Configuration();con.setMapUnderscoreToCamelCase(true);bean.setConfiguration(con);// 4.2: 分页插件// 4.2.1: 准备插件需要的参数Properties p = new Properties();// 4.2.2: 开启分页插件的固定写法p.setProperty("value","true");// 4.2.3: 创建分页插件对象PageInterceptor page = new PageInterceptor();// 4.2.4: 给分页插件设置参数page.setProperties(p);// 4.2.5 : 将分页插件交给SqlSessionFactoryBean管理bean.setPlugins(new Interceptor[]{page});// 5: 返回准备好的SqlSessionFactoryBean,spring的ioc管理 SqlSessionFactoryBean的时候,会自动从SqlSessionFactoryBean中获取SqlSessionFactoryreturn bean;}@Beanpublic MapperScannerConfigurer mapper(){MapperScannerConfigurer mapper = new MapperScannerConfigurer();// 设置要扫描的接口映射包mapper.setBasePackage(mapperPackage);return mapper;}
}

3.MySpringConfig类:ioc容器,spring统一管理的配置类

//纯注解的
@Configuration
@ComponentScan("com.spmvc.demo01_BookSystem")
@Import({DruidConfig.class,MyBatisConfig.class,SpringMvcSupport.class})
@PropertySource({"classpath:jdbc.properties"})
@EnableWebMvc
@EnableTransactionManagement
public class MySpringConfig {
}

 4.开启事务

/*专门处理mybatis的事务交给ioc容器的配置类*/
public class ShiWuConfig {@Beanpublic PlatformTransactionManager shiWu(DataSource ds){// 1: 创建mybatis的事务管理器对象DataSourceTransactionManager manager = new DataSourceTransactionManager();// 2: 给事务管理器设置一个连接池manager.setDataSource(ds);// 3: 返回事务管理器return manager;}
}

以上1.2.3.4是spring对mybatis配置的简化开发,且固定不变的

4.spring整合SpringMVC:SpringMvc将spring的核心配置类交给这个方法即可

// springmvc要求我们继承AbstractAnnotationConfigDispatcherServletInitializer类,重写三个方法,提供spring的核心容器和拦截路径
public class MySpringMVCConfig extends AbstractAnnotationConfigDispatcherServletInitializer {// web核心容器是什么,只需要将spring的核心配置类交给这个方法即可@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{MySpringConfig.class};}// 专门存放controller的容器,依然可以继续使用spring的ioc容器@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{MySpringConfig.class};}// 告诉web服务器,当浏览器发出什么样的请求的时候,我们就从专门存放controller的容器中获取controller对象,对浏览器进行处理@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}//乱码处理@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");return new Filter[]{filter};}
}

5.整合静态资源:设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {//当访问/pages/????时候,从/pages目录下查找内容registry.addResourceHandler("/pages/").addResourceLocations("/pages/");registry.addResourceHandler("/js/").addResourceLocations("/js/");        		registry.addResourceHandler("/css/").addResourceLocations("/css/");       registry.addResourceHandler("/plugins/").addResourceLocations("/plugins/");registry.addResourceHandler("/img/").addResourceLocations("/img/");}
}

以上4.5是对利用SpringMvc对spring的整合也称为ssm整合

运行:用Postman工具测试:

二、对响应结果再做统一格式

                原因:由于一个系统中,会进行各种不同的操作,如果每种操作都响应不同格式的结果,不利于前后端分离开发,

                           因此需要对后端响应数据做统一格式处理;

                好处:便于前后端分离开发时候的数据交互

                格式:会由3部分组成 1.状态码    2.提示信息  3.正文数据

参考代码:pojo层下Javabean中创建类+状态码(写一些的常量)

/*专门用于封装响应信息的统一格式的结果类*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyResult {// 包含三部分信息;  自定义的状态码   提示信息   正式数据private Integer code;private String msg;private Object data;
}public class MyStatusCode {public static final Integer SAVE_OK = 20001;public static final Integer DEL_OK = 20002;public static final Integer UPDATE_OK = 20003;public static final Integer GET_ONE_OK = 20004;public static final Integer GET_ALL_OK = 20005;public static final Integer SAVE_ERR = 20010;public static final Integer DEL_ERR = 20020;public static final Integer UPDATE_ERR = 20030;public static final Integer GET_ONE_ERR = 20040;public static final Integer GET_ALL_ERR = 20050;
}

对controller层改造  

 代码:controller层

@RestController
@RequestMapping(value = "/book")
public class BookController {@Autowiredprivate BookService bs;@GetMappingpublic MyResult selectAll() {List<Book> list = bs.selectAll();if (list != null && list.size() > 0) {//自定义的       状态码         提示信息      正式数据return new MyResult(MyStatusCode.GET_ALL_OK, "查询所有成功了", list);}return new MyResult(MyStatusCode.GET_ALL_ERR, "查询所有失败", null);}@GetMapping("/{name}")public MyResult selectByLikeName(@PathVariable String name) {List<Book> list = bs.selectByLikeName(name);if (list != null && list.size() > 0) {return new MyResult(MyStatusCode.GET_ONE_OK, "模糊查询成功拉", list);}return new MyResult(MyStatusCode.GET_ONE_ERR, "模糊查询失败", null);}@PostMappingpublic MyResult insertBook(@RequestBody Book book) {int i = bs.insertBook(book);if (i > 0) {return new MyResult(MyStatusCode.SAVE_OK, "添加成功拉", null);}return new MyResult(MyStatusCode.SAVE_ERR, "添加失败", null);}@DeleteMapping("/{id}")public MyResult delById(@PathVariable Integer id) {int i = bs.delById(id);if (i > 0) {return new MyResult(MyStatusCode.DEL_OK, "删除成功拉", null);}return new MyResult(MyStatusCode.DEL_ERR, "删除失败", null);}@PutMappingpublic MyResult updateById(@RequestBody Book book) {int i = bs.updateById(book);if (i > 0) {return new MyResult(MyStatusCode.UPDATE_OK, "修改成功拉", null);}return new MyResult(MyStatusCode.UPDATE_ERR, "修改失败", null);}
}

运行结果:

 三、SSM案例完成与HTML页面交互 

1.分页查询功能:

                           实现思路:

                                          1.浏览器给服务器发送请求的时候,必须携带分页相关参数和模糊查询的名称;因此需要在html页面

                                             发送请求,并从响应的结果中获取分页相关的集合和总条数两个数据

                                          2.controller中以json方式获取浏览器传递的参数,并将参数交给业务层查询,得到分页对象后封装到

                                             统一结果中响应给后端;

 

 

 

 然后改后台:

业务层接口:

业务层实现类 

 

pojo层:javaBean-简单的

 controller层进行修改:

 这就完成分页查询的功能了

 代码:

前端代码:

//主页列表查询getAll() {//alert(this.pagination.pageSize+"===>"+this.pagination.currentPage)axios({method: 'post',url: "http://localhost/book/getAllByPage",data: this.pagination}).then(resp => {// 获取结果对象中的状态码if(resp.data.code == 20005){// 把list集合的数据,交给 表格this.dataList = resp.data.data.list;this.pagination.total = resp.data.data.total;}else {// 失败,alert(resp.data.msg);}})},

service代码

@PostMapping("/getAllByPage")public MyResult selectAll(@RequestBody Pagination p){PageInfo<Book> pi = bs.selectAll(p.getCurrentPage(),p.getPageSize());if(pi.getList()!=null&&pi.getList().size()>0){return new MyResult(MyStatusCode.GET_ALL_OK,"查询所有成功拉",pi);}return new MyResult(MyStatusCode.GET_ALL_ERR,"查询所有失败",null);}impl@Overridepublic PageInfo<Book> selectAll(int currentPage, int pagesize) {//1:开启分页PageHelper.startPage(currentPage,pagesize);//2:正常查询List<Book> books = dao.selectAll();//3:封装结果PageInfo<Book> pi = new PageInfo<>(books);return pi;}

controller代码

    @PostMapping ("/getAllByPage")public MyResult selectAll(@RequestBody Pagination p) {PageInfo<Book> pi = bs.selectAll(p.getCurrentPage(),p.getPagesize());if (pi.getList() != null && pi.getList().size() > 0) {//自定义的       状态码         提示信息      正式数据return new MyResult(MyStatusCode.GET_ALL_OK, "查询所有成功了", pi);}return new MyResult(MyStatusCode.GET_ALL_ERR, "查询所有失败", null);}

模糊查询: