一、spring

1.1 spring框架

(1)框架的介绍和spring的介绍

  • 框架:一个半成品的软件架子
  • spring:一个基于Java编写的分层的JavaSE/EE应用的full [fʊl]- stack [stæk](一站服务式)轻量级开源的框架

(2)spring相关特点分析:

  • 分层:意思是说可以单独将它的某一功能进行抽取,单独使用该功能,也可以将整个spring框架拿过来使用。
  • JavaEE/SE:括揽web应用的全部层次(三层架构)和SE层次的功能。
  • full-stack:一站式服务式
  • 轻量级:占的内存比较少,是线程级的、非进程级的,所消耗的资源较少。
  • 开源:开放源代码,免费 。

1.1.1 spring 的体系结构

spring结构图.png
(1)Test模块:

  1. 集成了良好的单元测试功能

(2)core [kɔːr] container [kənˈteɪnə(r)]:核心容器(IoC容器所在的位置):里面包
含了各种jar包(黑色)

  1. Beans:就是Bean的容器,主要用来管理对象和依赖,以及依赖的注入
  2. Core:核心依赖包
  3. Context:上下文
  4. SpEL:spring的el表达式

(3)AOP与Aspects [æspɛkts] :面向切面

(4)数据访问呢集成

  1. JDBC:数据库连接集成
  2. ORM:对象映射关系集成
  3. OXM:对象与配置文件映射集成
  4. JMS:
  5. Transactions [træn’zækʃənz]:事务的集成

(4)Web:spring开发Web应用的模块

  1. websocket:新的技术,基于单个TCP连接,具有双向性的
  2. servlet:原生的web相关;
  3. web:开发web项目
  4. portlet:相关的组件

1.1.2 IoC与DI的认识 (创建对象)

(1)耦合与内聚

  • 耦合(Coupling [ˈkʌplɪŋ]):代码书写过程中所使用的技术的结合紧密度,用于衡量软件中各个模块之间的互联程度。
  • 内聚(Cohesion [koʊˈhiːʒn]):代码书写过程中单个模块内部各个组成部分间的联系,用于衡量软件中各个功能模块内部的功能联系

(2)程序书写的目的:高内聚,低耦合:就是同一个模块内中的各个元素之间要高度紧密,但各个模块之间的相互依存度却不要那么紧密。

  • IoC(Inversion [ɪnˈvɜːʃn] [ɪnˈvɜːrʒn] Of Control [kənˈtroʊl])控制反向控制应用程序所需要使用的外部资源。将创建对象的操作权交给spring,并由spring管理bean的生命周期
  • Spring控制的资源全部放置在Spring容器中,该容器成为IoC容器。
  • DI:将类中对象类型的成员变量进行装配赋值

1.1.3 Bean标签的使用及认识

  1. bean标签的基本认识

    • 名称:bean
    • 类型:标签
    • 归属:beans标签
    • 作用:定义spring资源中的资源,受此标签定义的资源将受到spring控制(即将该类注入到springIoc的容器中)
    • 格式:
      1. <beans>
      2. <bean />
      3. </beans>
  2. Bean标签相关的属性 | 属性名 | 说明 | | | —- | —- | —- | | id | bean的名称,通过id值获取bean(值是唯一的) | | | class | bean的类型(通常是接口或类的全类名) | | | name | bean的第二名称,因此可以通过name值获取bean(可以取多个值,用于多人配合开发时给bean取别名) | | | scope | 定义bean的作用范围;取值:①singleton [ˈsɪŋɡltən] :设定创建出的对象保存在spring容器中,是一个单例的对象,并且在获取spring容器(ApplicationContext)的时候创建对象;②prototype :设定创建出的对象保存在spring容器中,是一个非单例的对象,只有在使用bean(调用getBean方法)的时候创建bean;③request、session、application、websocket:设定创建出的对象放置在web容器对应的位置。 | |

1.1.4 依赖注入(DI)实操

(1)set注入

  1. 标签名:property
  2. 归属:bean标签
  3. 作用:使用set方法的形式为bean的属性赋值
  1. 代码实现
  • 步骤:

    • ①创建一个mavenWeb工程;
    • ②在pom文件中导入spring-framework的坐标 ; ```xml <?xml version=”1.0” encoding=”UTF-8”?> <project xmlns=”http://maven.apache.org/POM/4.0.0

      1. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      4.0.0

      com.xiaoha MySpring

      1.0-SNAPSHOT UTF-8 1.8 1.8

      org.springframework spring-context 5.1.20.RELEASE junit junit 4.11
  1. </dependencies>

  1. - ③创建service层的接口规范和实现类;
  2. ```java
  3. package com.xiaoha.service;
  4. import com.xiaoha.POJO.Person;
  5. import org.junit.Test;
  6. /**
  7. * @author HausenLee
  8. * @date 2021/04/03
  9. */
  10. public class PersonService {
  11. private Person person;
  12. public Person getPerson() {
  13. return person;
  14. }
  15. public void setPerson(Person person) {
  16. this.person = person;
  17. }
  18. public void MyTest(){
  19. String name = person.getName();
  20. System.out.println(name);
  21. }
  22. }
  • ④创建配置的xml文件; ```xml

<?xml version=”1.0” encoding=”UTF-8”?>

- ⑤在测试类中编写spring控制的代码进行servlet层调用service层的方法 。java package com.xiaoha.test; import com.xiaoha.POJO.Person; import com.xiaoha.service.PersonService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; / @author HausenLee @date 2021/04/03 */ public class TestSpring { public static void main(String[] args) { //默认创建的对象为单例的,而且在创建ClassPathXmlApplicationContext对象就把bean创建了 ApplicationContext personService = new ClassPathXmlApplicationContext(“application.xml”); //参数一为bean标签中的id值,参数二为指定bean的类型 PersonService persionService = personService.getBean(“personService”, PersonService.class); persionService.MyTest(); } } <a name="iJSRX"></a> #### (2)集合注入 1. List注入 1. 标签名:array、list、set、map、props 1. 归属:property标签或者constructor-arg标签 1. 作用:注入集合数据类型的属性(给数据类型为集合的属性赋值) 2. 代码演示: 1. 工程环境和上面的一样 1. 创建service层的逻辑java package com.xiaoha.service; import com.xiaoha.POJO.Person; import org.junit.Test; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; / @author HausenLee @date 2021/04/03 / public class PersonService { private List list; private int [] arr; private Map map; private Properties properties; public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public int[] getArr() { return arr; } public void setArr(int[] arr) { this.arr = arr; } public List getList() { return list; } public void setList(List list) { this.list = list; } public void TestList(){ for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } public void TestArray(){ for (int i : arr) { System.out.println(i); } } public void TestMap(){ Set keys = map.keySet(); for (String key : keys) { String value = map.get(key); System.out.println(“key”+key+”….”+”value”+value); } } public void TestProps(){ Set> entries = properties.entrySet(); for (Map.Entry entry : entries) { Object key = entry.getKey(); Object value = entry.getValue(); System.out.println(“key:”+key+”….”+”value:”+value); } } } c.创建xml配置文件xml <?xml version=”1.0” encoding=”UTF-8”?> xiaoha 张强 HausenLee 123 456 789 老子是值 老子还是值 <a name="VmiFW"></a> #### (3)构造器注入 1. 标签名:constructor [kənˈstrʌktər]: 1. 归属:bean标签 1. 作用:使用构造方法的形式为bean的属性赋值 1. 格式:xml 5. 属性列表 | 属性名 | 说明 | | --- | --- | | name | 指定构造函数中的参数名 | | value | 为基本数据类型的参数指定值 | | ref | 为引用数据类型的参数指定值 | | type | 指定参数的类型 | | index | 按参数的顺序索引指定 | <a name="NMSS7"></a> #### (4)级联属性赋值xml <a name="pi3yH"></a> #### (5)bean标签中的继承关系xml <a name="1aseL"></a> #### (6)bean标签中的依赖关系xml <a name="LTB9k"></a> #### (7) bean标签的生命周期 - 属性名称:init [ɪ'nɪt] -method, destroy [dɪˈstrɔɪ] -method - 作用:定义bean对象在初始化或销毁时完成工作 - 格式:xml <bean init-method=”init” destroy-method=”destroy> - 取值:bean对应的类中方法的名称 - 执行时机: - 当scope=“singleton”时,关闭容器会导致bean实例的销毁,这时就会调用destroy方法一次,创建bean对象时,init会被调用仅仅一次。 - 当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,destroy方法将不会被执行,创建bean对象时,创建几次init就会被调用几次。 <a name="OpnGI"></a> #### (8)通过工厂创建service 层实现类对象 - 属性名称:factory-bean,factory-method - 作用:定义bean对象的创建方式,使用静态实例工厂的形式创建bean,兼容早期遗留系统的升级工作。 - 格式:①工厂类静态调用方法方式xml ②创建工厂类的实例方式进行获取bean实例xml <a name="ZK7bv"></a> #### (9)BeanPostProcessor接口 1. BeanPostProcessor接口为后置处理器,自定义类实现了该接口,重写接口中的postProcessBeforeInitialization方法和postProcessAfterInitialization方法,可以在bean的初始化前后进行对bean的干预。 <a name="0NkTh"></a> #### (4)读取properties文件 - spring 提供了读取外部properties文件的机制,使用读取的数据为bean的属性赋值 - 操作步骤<br />①准备外部properties文件<br />②开启context命名空间支持<br />③加载指定的properties文件<br />④使用加载数据xml xmlns:context=”http://www.springframework.org/schema/context xml <context:property-plaoeholder location=”classpath:.properties”/> ```xml <property name="propertyName" value="${propertiesName}"/> - 注意:如果需要加载所有的properties文件,可以使用.properties表示加载所有的properties文件 ,其中${propertiesName}中的propertiesName指的是properties文件中的键名称。 #### (5)团队开发—-配置文件的导入 - 标签名称:import - 归属:beans标签 - 作用:在当前的配置文件中导入其他的配置文件的项 - 格式:

- 基本的属性 xml <import resource="配置文件名"> ### 1.1.5 spring整合mybatis案例 #### 1.1.5.1 xml配置文件方式 (1)整个案例的实现步骤 ①创建maven工程 ②在pom文件中导入相关依赖的坐标 xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- spring相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--spring整合jdbc相关的依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--数据源相关依赖&#45;&#45;druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <!--mybatis整合spring相关的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!-- mybatis相关的依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> ③搭建三层架构 - dao层代码实现 java package com.xiaoha.dao; import com.xiaoha.bean.User; import java.util.List; public interface UserDao { //添加保存数据 public abstract void save(); //查询所有的数据 public abstract List<User> findAll(); } - service层代码实现 java package com.xiaoha.service; import com.xiaoha.bean.User; import java.util.List; public interface UserService { //添加与保存数据的方法 public abstract void save(); //查询所有数据的方法 public abstract List<User> findAll(); } java package com.xiaoha.service.impl; import com.xiaoha.bean.User; import com.xiaoha.dao.UserDao; import com.xiaoha.service.UserService; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import java.util.List; public class UserServiceImpl implements UserService { private UserDao ud; public void setUd(UserDao ud) { this.ud = ud; } @Override public void save() { // System.out.println("UserServiceImpl running"); ud.save(); } @Override public List<User> findAll() { List<User> all = ud.findAll(); return all; } } - 测试类 java package com.xiaoha.test; import com.xiaoha.bean.User; import com.xiaoha.service.impl.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserServiceImpl userService = (UserServiceImpl) ac.getBean("userService"); //userService.save(); List<User> all = userService.findAll(); System.out.println(all); } } ④创建spring相关的核心配置文件——applicationContext.xml文件 xml <!--加载数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/xiao"/> <property name="username" value="root"/> <property name="password" value="960317"/> </bean> <!--加载service的bean--> <bean id="userService" class="com.xiaoha.service.impl.UserServiceImpl"> <property name="ud" ref="userDao"/> </bean> <!--加载mybatis核心资源--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="com.xiaoha.bean"/> </bean> <!--加载sql相关的映射资源--> <bean id="haha" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.xiaoha.dao"/> </bean> ⑤编写sql语句映射文件 ```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"> <a name="9e194ca7"></a> #### 1.1.5.2 spring的注解开发 <a name="wz5Sr"></a> #### (1)常用的注解 - 启动注解功能:启动注解扫描,加载类中的配置的注解项,该标签是写在applicationContext文件中的。xml - 扫描注解时可以排除一些不要的组件xml - 说明: - ①在进行包扫描时,会对配置的包及其子包中所有的文件进行扫描 - ②扫描过程是以文件夹递归迭代的形式进行的。 - ③扫描的过程仅读取合法的Java文件 - ④扫描时仅读取spring可识别的注解 - ⑤扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器中 - 注意: - ①无论是注解形式还是xml文件格式,最终都是将资源加载到IoC容器中 ,差别仅仅是数据读取的方式不同; - ②从加载效率上来说,注解优于xml配置文件。 <a name="qJoAD"></a> #### (2)bean的定义相关的注解 - 注解名称:@Component(主流) 、[@Controller ](/Controller ) (三层架构控制层用的注解)、@Service(三层架构服务层用的注解) 、@Repository(比较少用,一般用在dao层) - 类型:类注解(写在类名上面的) - 作用:设置该类为spring管理的bean - 范例:java @Component public class ClassName{} - 说明:[@Controller ](/Controller ) 、[@Service ](/Service ) 、@Repository是@Component的衍生注解,功能同[@Component ](/Component ) - 相关属性:value(默认属性):定义bean的访问id(不写的话默认是以类名首写字母小写名为id) <a name="oRNBr"></a> #### (3)bean的作用域相关的注解 - 注解名称:[@Scope ](/Scope ) - 类型:类注解(写在类名的上面) - 作用:设置该类作为bean对应的scope属性 - 范例:java @Scope public class ClassName{} - 相关的属性:value(默认属性):定义bean的作用域,默认取值为:singleton(单例bean对象),prototype(非单例bean对象) <a name="eMdCa"></a> #### (4)bean的声明周期相关的注解 - 注解名称:[@PostConstruct ](/PostConstruct )(初始化注解,初始化将调用该方法) 、 [@PerDestroy ](/PerDestroy )(销毁注解,销毁将调用该方法) - 类型:方法注解(写在方法上面的) - 作用:设置该类作为bean对应的声明周期方法 - 范例:java @PostConstruct public void init(){} @PerDestroy public void destroy(){} <a name="ulbXk"></a> #### (5)加载第三方资源的注解方式 - 注解名称:[@Bean ](/Bean ) - 类型:方法注解 - 作用:设置该方法的返回值作为spring管理的bean - 范例:java @Bean(“dataSource”) public DruidDataSource createDataSource(){ return ……; } - 该注解用于替换xml配置文件中的静态工厂与实例工厂创建bean,不区分方法是否为静态或非静态。 - 相关属性:value(默认):定义bean的访问的id <a name="9e039"></a> #### (6)bean的非引用类型属性的注入 - 注解名称:[@Value ](/Value ) - 类型:属性注解,方法注解 - 作用:设置对应属性的值或方法进行传参。 - 范例:java @Value(“${jdbc.username}”) private String username; - 说明: - ①Value值支持非引用的数据类型 - ②Value值支持读取properties文件中的属性值,通过类属性将properties文件中的数据传入类中 - ③可以省去给属性赋值set方法。 - 相关属性:value(默认):定义对应的属性值或参数值 <a name="wNdzQ"></a> #### (7)bean的引用类型属性注入相关注解(自动装配) - 注解名称:[@Autowired ](/Autowired ) 、[@Qualifier ](/Qualifier )(如果有多个bean组件加载到Ioc容器中,当使用@Autowired注解进行自动装配时,它首先会根据成员变量的类型进行匹配,如果类型相同,则会根据变量名进行匹配,一般如果有多个组件加载到Ioc容器中,我们会对组件设置一个id来区分,然后通过 @Autowired主键和@Qualifier注解进行根据id来获取bean) - 类型:属性注解、方法注解 - 作用:设置对应属性的对象或对方法进行引用类型传参 - 范例:java @Autowired(required=false) @Qualifier(“userDao”) private UserDao userDao; / 方法上有@Autowired注解: 1.这个方法也会在bean创建的时候自动装配 2.这个方法的每个参数都会注入值 3.@Qualifier注解会为bean指定id进行匹配(原本是利用属性名指定bean) / @Autowired public void test(BookDao bookDao , @Qualifier(“bookService”)BookService bookService){ System.out.println(“Spring运行了这个方法…….”+ bookDao+”==>”+ bookService); } - 说明: @Autowired默认按类型装配,指定@Qualifier后可以指定自动的装配的bean的id - 相关属性:required:定义该类属性是否允许为null 扩展:自动装配的注解有:Autowired、Resource、Inject<br />Autowired:最强大;Spring框架自己的注解;<br />Resource:扩展性强;因为是Java的标准,如果切换成另外一个容器框架,Resource注解还是可以使用的, <a name="kP7aw"></a> #### (8)加载properties文件 - 注解名称:[@PropertySource ](/PropertySource ) - 类型:类注解 - 作用:加载properties文件中的属性值 - 范例:java @PropertySource(value=”classpath:文件名.properties”) public class ClassName{ @Value(“${propertiesAttributeName}”) private String attributeName; } - 说明:不支持通配格式,一旦加载,所有的spring控制的bean中均可使用对应的属性值 - 相关属性:value(默认):设置加载的properties文件名 - ignoreResourceNotFound:如果资源未找到,是否忽略,默认为false <a name="2ByFh"></a> #### (9)泛型案例 1. 配置文件xml <?xml version=”1.0” encoding=”UTF-8”?> 2. dao层代码java / dao层父类 */ package org.xiaoha.dao; import org.springframework.stereotype.Repository; / @author HausenLee @date 2021/04/11 / @Repository public abstract class BaseDao { public abstract boolean save(Object o); } / dao层子类 / package org.xiaoha.dao; import org.springframework.stereotype.Repository; import org.xiaoha.pojo.Book; /** @author @date / @Repository public class BookDao extends BaseDao { @Override public boolean save(Object o) { System.out.println(“正在保存书籍………”); return false; } } package org.xiaoha.dao; import org.springframework.stereotype.Repository; import org.xiaoha.pojo.User; / @author @date / @Repository public class UserDao extends BaseDao { @Override public boolean save(Object o) { System.out.println(“正在保存用户…….”); return false; } } 3. service层代码java / service层父类 */ package org.xiaoha.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.xiaoha.dao.BaseDao; / @author @date / //@Service public class BaseService { @Autowired // @Qualifier(“baseDao”) private BaseDao baseDao; public boolean save(Object o) { baseDao.save(o); return true; } } / service层子类 / package org.xiaoha.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.xiaoha.dao.BaseDao; import org.xiaoha.pojo.Book; import org.xiaoha.service.BookService; /** @author @date / @Service public class BookServiceImpl extends BaseService{ // @Autowired // private BaseDao baseDao; // @Override // public boolean save(Object o) { // // return true; // } } package org.xiaoha.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.xiaoha.dao.BaseDao; import org.xiaoha.pojo.User; import org.xiaoha.service.UserService; / @author @date */ @Service public class UserServiceImpl extends BaseService{ // @Autowired // private BaseDao baseDao; // // @Override // public boolean save(Object o) { // // return true; // } } 3. 测试/controller层java package org.xiaoha.controller; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.xiaoha.pojo.Book; import org.xiaoha.pojo.User; import org.xiaoha.service.impl.BookServiceImpl; import org.xiaoha.service.impl.UserServiceImpl; / @author @date / public class Controller { private ApplicationContext ioc = new ClassPathXmlApplicationContext(“fanxing.xml”); @Test public void myTest(){ UserServiceImpl userService = ioc.getBean(UserServiceImpl.class); BookServiceImpl boo = ioc.getBean(BookServiceImpl.class); User u= new User(); Book b = new Book(); userService.save(u); boo.save(b); } } <a name="894bc188"></a> #### 1.1.5.3纯注解开发 (1)纯注解开发格式及注解 - 注解名称:@Configuration、[@ComponentScan ](/ComponentScan ) - 类型:类注解 - 作用:设置当前类为spring核心配置加载类 - 范例:java @Configuration @ComponentScan(“scanPackageName”) public class SpringConfigClassName{} - 说明:核心配合类用于替换spring核心配置文件,此类可以设置空的,不设置变量与属性 (2)案例实现步骤 ①搭建maven工程 ②导入相关依赖坐标 ③搭建三层架构 - dao层代码实现java package com.xiaoha.dao; import com.xiaoha.bean.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import java.util.List; public interface UserDao { //添加保存数据 @Insert(“insert into user values (null,#{name},#{password})”) public abstract void save(); //查询所有的数据 @Select(“select from user”) public abstract List findAll(); } - service层代码实现及配置类java package com.xiaoha.service; import com.xiaoha.bean.User; import java.util.List; public interface UserService { //添加与保存数据的方法 public abstract void save(); //查询所有数据的方法 public abstract List findAll(); } ```java package com.xiaoha.service.impl; import com.xiaoha.bean.User; import com.xiaoha.dao.UserDao; import com.xiaoha.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import java.util.List; @Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void save() { userDao.save(); } @Override public List<User> findAll() { List<User> all = userDao.findAll(); return all; } } - 配置类 java package com.xiaoha.config; import com.alibaba.druid.pool.DruidDataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; public class SqlConfig { /** * mybatis配置类 * * */ @Bean public MapperScannerConfigurer getMapperScannerConfigurer(){ /** * sql映射配置 */ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.xiaoha.dao"); return msc; } @Bean public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DruidDataSource dataSource){ /** * 起别名配置 */ SqlSessionFactoryBean sfb = new SqlSessionFactoryBean(); sfb.setTypeAliasesPackage("com.xiaoha.bean"); sfb.setDataSource(dataSource); return sfb; } } java package com.xiaoha.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; public class JDBCConfig { /** * 数据源配置类 */ @Value("${driver}") private String driverClassName; @Value("${url}") private String url; @Value("${jdbc.username}") private String username; @Value("${password}") private String password; @Bean("dataSource") public DruidDataSource getDruidDataSource(){ DruidDataSource dds = new DruidDataSource(); dds.setDriverClassName(driverClassName); dds.setUrl(url); dds.setUsername(username); dds.setPassword(password); return dds; } } java package com.xiaoha.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.PropertySource; //标注识别的配置类 @Configuration //扫描指定包下的bean注解类 @ComponentScan("com.xiaoha") //导入其他的配置类 @Import({JDBCConfig.class,SqlConfig.class}) //引入读取properties文件中的数据 @PropertySource("classpath:abc.properties") public class SpringConfig { } - 测试类 java package com.xiaoha.test; import com.xiaoha.bean.User; import com.xiaoha.config.SpringConfig; import com.xiaoha.service.impl.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class Test { public static void main(String[] args) { ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class); UserServiceImpl userService = ac.getBean("userService", UserServiceImpl.class); List<User> all = userService.findAll(); System.out.println(all); //userService.save(); } } #### 1.1.5.4xml配置文件加上注解开发 (1)案例实现步骤 ①搭建maven工程 ②导入相关的依赖坐标 ③搭建三层架构 - dao层代码实现 java package com.xiaoha.dao; import com.xiaoha.bean.User; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import java.util.List; public interface UserDao { //添加保存数据 @Insert("insert into user values (null,#{name},#{password})") public abstract void save(); //查询所有的数据 @Select("select * from user") public abstract List<User> findAll(); } - service层代码实现 java package com.xiaoha.service; import com.xiaoha.bean.User; import java.util.List; public interface UserService { //添加与保存数据的方法 public abstract void save(); //查询所有数据的方法 public abstract List<User> findAll(); } java package com.xiaoha.service.impl; import com.xiaoha.bean.User; import com.xiaoha.dao.UserDao; import com.xiaoha.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import java.util.List; @Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void save() { userDao.save(); } @Override public List<User> findAll() { List<User> all = userDao.findAll(); return all; } } - spring核心配置文件 xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation= "http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd "> <context:component-scan base-package="com.xiaoha"/> <!-- 引入加载properties文件中的数据--> <context:property-placeholder location="classpath:abc.properties"/> <!--加载druid数据源相关的bean--> <bean id="dataSource" 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> <!--加载sqlSessionFactory的bean--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--起别名--> <property name="typeAliasesPackage" value="com.xiaoha.bean"/> </bean> <!-- 加载sql映射相关的bean--> <bean id="sql" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.xiaoha.dao"/> </bean> </beans> - 测试类代码实现 java package com.xiaoha.test; import com.xiaoha.bean.User; import com.xiaoha.service.impl.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserServiceImpl userService = ac.getBean("userService", UserServiceImpl.class); List<User> all = userService.findAll(); System.out.println(all); //userService.save(); } } ## 1.2 AOP (1)AOP的认识 - AOP(Aspect Oriented Programing) 面向切面编程思想,一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构。 (2)AOP相关的概念 - Joinpoint(连接点):类里面哪些方法可以被增强,这些方法称之为连接点 - Pointcut(切入点):实际被真正增强的方法,称之为切入点 - Advice(通知):实际增强的逻辑代码部分称之为通知(增强) - Aspect(切面):是动作:就是把通知应用到切入点的过程 - Target(目标对象):就是被挖掉的共性代码所在的类产生的对象。 - Weaving(织入):将挖掉的代码回填的动态过程。 - proxy(代理):通过代理对象把被挖掉的共性代码进行回填 - introduction(引入\引介):无中生有添加成员变量,成员方法 ### 1.2.1 AOP配置文件方式相关知识点 (1)AspectJ - Aspect(切面):用于描述切入点域通知之间的关系,是AOP编程中的一个概念,spring框架一般都是基于AspectJ实现AOP操作的。 - AspectJ是基于java语言对Aspect的实现,它不是spring组成的一部分,是一个独立的AOP框架。 - 基于AspectJ实现Aop操作有两种方式: - 基于xml配置文件实现 - 基于注解方式实现(这种方式在实际开发中经常用。) (2)AOP配置 - 标签名称:aop:config - 归属:beans标签 - 作用:设置AOP - 格式: xml <beans> <aop:config>......</aop:config> <aop:config>......</aop:config> <aop:config>......</aop:config> ...... </beans> - 说明:一个beans标签中可以配置多个aop:config标签 (3)aop:pointcut - 标签名称:aop:pointcut - 归属:aop:config 、aop:aspect标签 - 作用 :设置切入点 - 格式: xml <aop:config> <aop:pointcut id="pointcutId" expression="execution(指定的通知方法名)"/> <aop:aspect> <aop:pointcut id="pointcutId" expression="execution(指定的通知方法名)"/> </aop:aspect> </aop:config> - 说明:一个aop:config标签中可以配置多个aop:pointcut标签,且该标签可以配置在aop:aspect标签内。 - 基本属性:①id:识别切入点的名称;②expression:切入点表达式。 (4)切入点表达式 - 作用:切入点表达式是一个快速匹配方法描述的通配格式 ,类似于正则表达式。 - 格式:execution(访问权限符 返回值类型 类的全类名/接口的全类名 方法名(参数列表)异常名) - 范例: xml <!--例一:对com.xiaoha.dao.UserDao类里面的add方法进行增强--> execution(* com.xiaoha.dao.UserDao.add(..)) <!--例二:对com.xiaoha.dao.UserDao类里面的所有方法进行增强--> execution(* com.xiaoha.dao.UserDao.*(..)) execution(public User com.xiaoha.service.UserService.findById(int)) (5)切入点表达式——通配符 - :表示单个独立的任意符号,可以独立出现,也可以作为前缀或后缀的匹配符出现。 - .. :表示多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写。 - + :专用于匹配子类类型 (6)AOP的5种通知类型 - 前置通知:原始方法执行前执行,before;应用的场景:数据的校验,事务的开启 - 后置通知:原始方法执行后执行,after :应用场景:现场清理 ,释放资源 - 返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行;after-returning。应用场景:返回值相关数据的处理,事务的提交 - 抛出异常后通知:原始方法抛出异常后执行,没有异常则不执行,after-throwing;应用场景:对原始数据的异常进行处理。 - 环绕通知:在原始方法执行前后均有对应的执行。还可以阻止原始方法的执行,应用场景:十分强大,可以做任何事情。 环绕通知连接点的方法格式: java public Objcet around (ProceedingJoinPoint pjp) throws Throwable{ Object ret = pjp.proceed(); return ret; } ### 1.2.2 AOP入门案例 (1)实现步骤 - 搭建maven工程 - 搭建三层架构 - 导入相关的依赖坐标 - 创建编写spring核心配置文件:①配置加载service层实现类的bean到IoC容器中;②配置加载封装共性代码的类的bean到IoC容器中。③添加aop相关的名称空间;④配置AOP;代码实现如下: ```xml <?xml version=”1.0” encoding=”UTF-8”?> <aop:pointcut id=”pt” expression=”execution( com..(..))”/> - 注意:测试的时候,要通过service层的接口规范约束以多态的形式进行接收:java package com.xiao.test; import com.xiao.service.UserService; import com.xiao.service.impl.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationConfig.xml”); UserService userService = (UserService) ac.getBean(“userService”); userService.save(); } } <a name="b6ad2dd3"></a> ### 1.2.3AOP通知获取参数数据及返回值 (1)设定通知方法第一个参数为JoinPoint,通过该对象调用getArgs()方法,获取原始方法运行的参数数组。java public void before (JoinPoint jp) throws Throwable{ Object[] args=jp.getArgs(); } - 所有的通知均可获取参数。 (2)after-returning获取返回值 - 原始方法java public int save(){ System.out.println(“user service running…”); return 100; } - AOP配置xml <aop:pointcut id=”pt” expression=”execution( ..(..))”/> - 通知类java public void afterReturning(Object ret){ System.out.println(ret); } - 适用于返回后通知(after-returning) (3)round获取返回值。 - 原始方法:java public int save (){ System.out.println(“user service running…”); return 100; } - AOP配置xml - 通知类java public Object around(ProceedingJoinPoint pjp)throws Throwable{ Object ret =pjp.proceed(); return ret; } - 适用于around通知 <a name="9f6d7b83"></a> ### 1.2.4 AOP注解开发 (1)Aspect注解 - 注解名称:[@Aspect ](/Aspect ) - 类别名称:类注解 - 作用:设置当前类为切面类 - 格式:java @Aspect public class AopAdvice{ } - 说明:一个bean标签中可以配置多个aop:config标签 (2)Pointcut注解 - 注解名称:[/](/Pointcut ) - 类型:方法注解 - 作用:使用当前方法名作为切入点引用名称 - 格式:java @Pointcut(“execution( ..(..))”) public void pt(){ } - 说明:被修饰的方法忽略器业务功能,格式设定为无惨无返回值的方法,方法体内 空实现(非抽象)。 (3)Before注解 - 注解名称:[@Before ](/Before ) - 类型:方法注解 - 作用:标注当前方法作为前置通知 - 格式:java @Before(“pt()”) public void before(){ } - 特殊参数:无。 (4)After注解 - 注解名称:[@After ](/After ) - 类型:方法注解 - 作用:标注当前方法作为后置通知 - 格式:java @After(“pt()”) public void after(){ } - 特殊参数:无 (5)AfterReturning注解 - 名称:[@AfterReturning ](/AfterReturning ) - 类型:**注解** - 位置:方法定义上方 - 作用:标注当前方法作为返回后通知 - 格式:java @AfterReturning(value=”pt()”,returning = “ret”) public void afterReturning(Object ret) { } <a name="177b052b"></a> # 二、spring - mvc的基本操作与认识 (1)springmvc简介 - springmvc是一种基于java实现mvc模型的轻量级web框架,基于三层架构的(controller)表现层 - springmvc的优点:①使用简单②性能突出③灵活性强。 <a name="4caf4a50"></a> ## 2.1 spring - mvc的入门操作 (1)实现步骤: ①搭建maven工程 ②导入相关的依赖坐标xml <?xml version=”1.0” encoding=”UTF-8”?> 4.0.0 com.xiao spring_MVC 1.0-SNAPSHOT war UTF-8 1.8 1.8 javax.servlet javax.servlet-api 3.1.0 provided javax.servlet.jsp javax.servlet.jsp-api 2.3.3 provided org.springframework spring-context 5.1.9.RELEASE org.springframework spring-webmvc 5.1.9.RELEASE org.springframework spring-web 5.1.9.RELEASE org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 / ③创建spring相关的核心配置文件xml <?xml version=”1.0” encoding=”UTF-8”?> ④在web.xml核心配置文件中配置servlet的拦截分配标签xml <?xml version=”1.0” encoding=”UTF-8”?> DispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-mvc.xml DispatcherServlet / ⑤创建测试的java工程 (表现层业务功能实现)java package com.xiao.ha.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller(“demoController”) public class DemoController { @RequestMapping(“/save”) public String save(){ System.out.println(“spring mvc running”); return “succeed.jsp”; } } <a name="8339688e"></a> ## 2.2 springmvc技术架构图 (1)组件简介 - DispatcherServlet:前端控制器,是整体流程的控制中心,由其调用其他的组件处理用户的请求,有效的降低了组件之间的耦合性。 - HandlerMapping:处理器映射器,负责根据用户请求找到对应的具体的handler处理器。 - Handler:处理器,业务处理的核心类,通常由开发者编写,描述具体的业务。 - HandlerAdapter:处理器适配器,通过他对处理器进行执行。 - View Resolver:视图解析器,将处理的结果生成View视图。 - View:视图,最终产出的结果,常用视图入jsp、html等。 (2)组件之图 <a name="e8c400a1"></a> ## 2.3 Controller层的基本加载控制 (1)controller层的servlet的基本控制 - 在web.xml文件中配置了servlet的拦截配置标签后 ,在spring核心配置文件中配置指定放行的bean过滤器和静态资源。配置如下:xml <?xml version=”1.0” encoding=”UTF-8”?> <a name="39fc275e"></a> ## 2.4 处理中文乱码的问题 - 在web.xml核心配置文件中配置spring提供的解决中文乱码的问题xml CharacterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding true CharacterEncodingFilter / ` text/html;charset=UTF-8 application/json;charset=UTF-8 /;charset=UTF-8 解决控制台乱码的问题 直接在pom文件中的tomcat插件配置xml utf-8 <a name="24c039d3"></a> ## 2.5 springmvc框架的请求 (1)普通类型的请求参数的传递 - 接收请求参数不论是get请求还是post请求,直接在方法中定义一个形参来接收就可以了。有几个就定义几个。 - 如果请求参数的键名与方法中的形参名不同则就要在形参前面加@RequestParam注解了 - 主要的注解:@RequestMapping,该注解为类注解、方法注解,可以写在类、方法的上面 。写在类的上面,其参数为访问方法的父路径,写在方法上面,其参数则为写在类上面的子路径。java @RequestMapping(“/被访问的servlet的路径”) public String requestParam(@RequestParam( //name表示的是方法的形参,userName表示的是请求参数的键 name=”userName”, //required表示的是请求参数是否必须,为true则为必须穿参数 required=true, defaultValue=”默认值” )String name){ System.out.println(“name”+name); return “跳转的页面”; } (2)引用类型(POJO)的请求参数的传递 - 直接根据引用数据类型(javabean)中的属性(成员变量)进行请求参数的传递,如果其中还有引用类型的属性(成员变量)则通过一级属性(第一个javabean中的引用类型的属性)点上二级属性(第一个javabean中的引用类型的属性中的属性)进行访问java //javabean类型的请求参数的传递 //http://localhost/save?name=zhangsan&age=18&Site.city=changsha&Site.home=zhijiang @RequestMapping(“/save”) public String save(User user){ System.out.println(user); System.out.println(); return “picture.jsp”; } - 引用类型中含有list集合的属性对请求参数的封装传递:通过list属性的属性名重复传参就可以了java //http://localhost/save?niko=gouzi&niko=ergouzi&niko=gousheng - 引用类型中含有List集合且其泛型为引用类型的,则根据集合的索引来进行传参就可以了。java //http://localhost/save?sites[0].city=changsha&sites[0].home=zhijiang - 引用类型中包含Map集合的,根据集合的键来进行传参java //http://localhost/save?siteMap['host'].city=changsha&siteMap['host'].home=zhijiang (3)数组与集合类型参数传参 - 数组类型的请求参数 传参:保存简单类型数据,请求参数名与处理器方法形参名保持一致,且请求参数数量> 1个java // http://localhost/requestParam10?nick=Jockme&nick=zahc @RequestMapping(“/requestParam10”) public String requestParam10(String nick){ System.out.println(nick); return “page.jsp”; } - 集合类型的请求参数的传参:保存简单类型数据,请求参数名与处理器方法形参名保持一致,且请求参数数量> 1个java // http://localhost/requestParam10?nick=Jockme&nick=zahc @RequestMapping(“/requestParam10”) public String requestParam10(@RequestParam(“nick”) List nick){ System.out.println(nick); return “page.jsp”; } 值得注意的是: SpringMVC默认将List作为对象处理,赋值前先创建对象,然后将nick作为对象的 属性进行处理。由于List是接口,无法创建对象,报无法找到构造方法异常;修复类型为可创建对象的ArrayList类型后,对象可以创建,但没有nick属性,因此数据为空。此时需要告SpringMVC的处理器nick是一组数据,而不是一个单一数据。通过@RequestParam注解,将数量大于1个names参数打包成参数数组后, SpringMVC才能识别该数据格式,并判定形参类型是否为数组或集合,并按数组或集合对象的形式操作数据。 <a name="e767dc8d"></a> ## 2.6 类型转换器 SpringMVC对接收的数据进行自动类型转换,该工作通过Converter接口实现 下图就是Converter接口及其实现类 对上图各种的实现类进行注解: - 标量的类型转换:<br /> StringToBooleanConverter String→Boolean<br /> ObjectToStringConverter Object→String<br /> StringToNumberConverterFactory String→Number( Integer、 Long等)<br /> NumberToNumberConverterFactory Number子类型之间(Integer、 Long、 Double等)<br /> StringToCharacterConverter String→java.lang.Character<br /> NumberToCharacterConverter Number子类型(Integer、 Long、 Double 等)→java.lang.Character<br /> CharacterToNumberFactory java.lang.Character→Number子类型(Integer、 Long、 Double等)<br /> StringToEnumConverterFactory String→enum类型<br /> EnumToStringConverter enum类型→String<br /> StringToLocaleConverter String→java.util.Local<br /> PropertiesToStringConverter java.util.Properties→String<br /> StringToPropertiesConverter String→java.util.Properties - 对于数组集合类型的转换:<br /> ArrayToCollectionConverter 数组→集合( List、 Set)<br /> CollectionToArrayConverter 集合( List、 Set) →数组<br /> ArrayToArrayConverter 数组间<br /> CollectionToCollectionConverter 集合间( List、 Set)<br /> MapToMapConverter Map间<br /> ArrayToStringConverter 数组→String类型<br /> StringToArrayConverter String→数组, trim后使用“,”split<br /> ArrayToObjectConverter 数组→Object<br /> ObjectToArrayConverter Object→单元素数组<br /> CollectionToStringConverter 集合( List、 Set) →String<br /> StringToCollectionConverter String→集合( List、 Set), trim后使用“,”split<br /> CollectionToObjectConverter 集合→Object<br /> ObjectToCollectionConverter Object→单元素集合 - 默认转换器:<br /> ObjectToObjectConverter Object间<br /> IdToEntityConverter Id→Entity<br /> FallbackObjectToStringConverter Object→String <a name="b5bb8741"></a> ## 2.7 日期类型转换器 (1)配置文件方式 - 声明自定义转换的格式 :xml (2)注解方式: - 日期类型转换的注解方式:<br />①注解名称: [@DateTimeFormat ](/DateTimeFormat ) <br />②类型: 形参注解、成员变量注解<br />③位置:形参前面 或 成员变量上方<br />④作用:为当前参数或变量指定类型转换规则<br />⑤范例:java //形参前面 public String requestParam12(@DateTimeFormat(pattern = “yyyy-MM-dd”) Date date){ System.out.println(“date=”+date); return “page.jsp”; } //成员变量上面 @DateTimeFormat(pattern = “yyyy-MM-dd”) private Date birthday; <a name="31ac02e4"></a> ## 2.8 spring-mvc的响应 (1)请求转发与请求重定向 - 请求转发:该跳转方式为默认方式。java @RequestMapping(“/showPage1”) public String showPage1() { System.out.println(“user mvc controller is running …”); return “forward:page.jsp”; } - 请求重定向:java @RequestMapping(“/showPage2”) public String showPage2() { System.out.println(“user mvc controller is running …”); return “redirect:page.jsp”; } 注意:return 的字符串中的“/”表示绝对路径,无“/”则表示相对路径。 - 访问页面的快捷方式 (InternalResourceViewResolver)xml /bean> 设定好了之后,java中的业务代码就可以这样写:java public String showPage3() { return “page”; } (2)带数据的页面跳转 - 方式一:使用HttpServletRequest类型形参进行数据传递java @RequestMapping(“/showPageAndData1”) public String showPageAndData1(HttpServletRequest request) { request.setAttribute(“name”,”itheima”); return “page”; } - 方式二:使用Model类型形参进行数据传递java @RequestMapping(“/showPageAndData2”) public String showPageAndData2(Model model) { //往mode里面设置响应的数据 model.addAttribute(“name”,”itheima”); Book book = new Book(); book.setName(“SpringMVC入门实战”); book.setPrice(66.6d); model.addAttribute(“book”,book); return “page”; } 方式三:使用ModelAndView类型形参进行数据传递,将该对象作为返回值传递给调用者java //使用ModelAndView形参传递参数,该对象还封装了页面信息 @RequestMapping(“/showPageAndData3”) public ModelAndView showPageAndData3(ModelAndView modelAndView) { //ModelAndView mav = new ModelAndView(); 替换形参中的参数 Book book = new Book(); book.setName(“SpringMVC入门案例”); book.setPrice(66.66d); //添加数据的方式,key对value modelAndView.addObject(“book”,book); //添加数据的方式,key对value modelAndView.addObject(“name”,”Jockme”); //设置页面的方式,该方法最后一次执行的结果生效 modelAndView.setViewName(“page”); //返回值设定成ModelAndView对象 return modelAndView; } (3)返回json数据 - 使用SpringMVC提供的消息类型转换器将对象与集合数据自动转换为JSON数据java //使用SpringMVC注解驱动,对标注@ResponseBody注解的控制器方法进行结果转换,由于返回值为引用类型,自动调用jackson提供的类型转换器进行格式转换 @RequestMapping(“/showData4”) @ResponseBody public Book showData4() { Book book = new Book(); book.setName(“SpringMVC入门案例”); book.setPrice(66.66d); return book; } 这种方法需要配置信息类型的转换器java <a name="9890172e"></a> ### 2.8.1 作业案例(登录的案例【连接数据库】) <a name="e1d527de"></a> #### ① 相关的pom文件的坐标依赖于插件xml <?xml version=”1.0” encoding=”UTF-8”?> 4.0.0 com.xiao.ha springlogin 1.0-SNAPSHOT war UTF-8 1.8 1.8 javax.servlet javax.servlet-api 3.1.0 provided javax.servlet.jsp javax.servlet.jsp-api 2.3.3 provided org.springframework spring-context 5.1.9.RELEASE org.springframework spring-webmvc 5.1.9.RELEASE org.springframework spring-web 5.1.9.RELEASE junit junit 4.11 test <!—mybatis相关的依赖—> org.mybatis mybatis 3.5.3 mysql mysql-connector-java 5.1.46 com.alibaba druid 1.1.21 jstl jstl 1.2 com.fasterxml.jackson.core jackson-annotations 2.9.0 com.fasterxml.jackson.core jackson-core 2.9.0 com.fasterxml.jackson.core jackson-databind 2.9.0 org.apache.poi poi 4.0.1 org.apache.poi poi-ooxml 4.0.1 org.springframework spring-jdbc 5.1.9.RELEASE org.mybatis mybatis-spring 1.3.0 org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 / <a name="a471fc42"></a> #### ②spring相关的核心配置文件的配置xml <?xml version=”1.0” encoding=”UTF-8”?> text/html;charset=UTF-8 application/json;charset=UTF-8 /*;charset=UTF-8

<?xml version=”1.0” encoding=”UTF-8”?>

<a name="58e4d9d5"></a> #### ③web.xml文件中的相关配置xml <?xml version=”1.0” encoding=”UTF-8”?> DispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-mvc.xml DispatcherServlet / org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath:applicationContext.xml <a name="4af907b5"></a> # 三、spring - mvc的进阶操作与认识 <a name="38a71126"></a> ## 3.1 接收异步请求参数 - 接收请求参数的注解<br /> 名称: [@RequestBody ](/RequestBody ) <br /> 类型: 形参注解<br /> 位置:处理器类中的方法形参前方<br /> 作用:将异步提交数据组织成标准请求参数格式,并赋值给形参<br /> 范例:java @RequestMapping(“/ajaxController”) public String ajaxController(@RequestBody String message){ System.out.println(message); return “page.jsp”; } - 注解添加到Pojo参数前方时,封装的异步提交数据按照Pojo的属性格式进行关系映射 - 注解添加到集合参数前方时,封装的异步提交数据按照集合的存储结构进行关系映射java @RequestMapping(“/ajaxPojoToController”) //如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中 //注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射 public String ajaxPojoToController(@RequestBody User user){ System.out.println(“controller pojo :”+user); return “page.jsp”; } @RequestMapping(“/ajaxListToController”) //如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中 public String ajaxListToController(@RequestBody List userList){ System.out.println(“controller list :”+userList); return “page.jsp”; } <a name="a6f435fe"></a> ## 3.2 异步请求接收响应数据 - 方法返回值为Pojo时,自动封装数据成json对象数据java @RequestMapping(“/ajaxReturnJson”) @ResponseBody public User ajaxReturnJson(){ System.out.println(“controller return json pojo…”); User user = new User(); user.setName(“Jockme”); user.setAge(40); return user; } - 方法返回值为List时,自动封装数据成json对象数组数据java @RequestMapping(“/ajaxReturnJsonList”) @ResponseBody //基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据 public List ajaxReturnJsonList(){ System.out.println(“controller return json list…”); User user1 = new User(); user1.setName(“Tom”); user1.setAge(3); User user2 = new User(); user2.setName(“Jerry”); user2.setAge(5); ArrayList al = new ArrayList(); al.add(user1); al.add(user2); return al; } <a name="ff7aa19f"></a> ## 3.3 针对异步请求的跨域访问 - 什么是跨域访问?跨域访问是别人的页面访问自己页面的资源,它默认是不允许的,而自己的页面访问自己的页面是允许的。 <a name="af7ad936"></a> ## 3.4 跨域环境的搭建 - 为当前主机添加备用域名 - 修改windows安装目录中的host文件 - 格式: ip 域名 - 动态刷新DNS - 命令: ipconfig /displaydns - 命令: ipconfig /flushdns - 跨域访问的支持<br /> 名称: [@CrossOrigin ](/CrossOrigin ) <br /> 类型: 方法注解 、 类注解<br /> 位置:处理器类中的方法上方 或 类上方<br /> 作用:设置当前处理器方法/处理器类中所有方法支持跨域访问<br /> 范例:java @RequestMapping(“/cross”) @ResponseBody //使用@CrossOrigin开启跨域访问 //标注在处理器方法上方表示该方法支持跨域访问 //标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问 @CrossOrigin public User cross(HttpServletRequest request){ System.out.println(“controller cross…”+request.getRequestURL()); User user = new User(); user.setName(“Jockme”); user.setAge(39); return user; } <a name="6d26e250"></a> ## 3.5 拦截器 (1)自定义拦截器 ①实现interceptor接口java //自定义拦截器需要实现HandleInterceptor接口 public class MyInterceptor implements HandlerInterceptor { //处理器运行之前执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(“前置运行——a1”); //返回值为false将拦截原始处理器的运行 //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行 return true; } //处理器运行之后执行 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println(“后置运行——b1”); } //所有拦截器的后置执行全部结束后,执行该操作 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println(“完成运行——c1”); } //三个方法的运行顺序为 preHandle -> postHandle -> afterCompletion //如果preHandle返回值为false,三个方法仅运行preHandle } ②在springmvc配置文件中配置拦截器xml …… …… <a name="71af6658"></a> ### 3.5.1 拦截器的执行流程 - 在handle类中没有异常的情况下:preHandle中返回值为true(不拦截)的话,则先执行preHandle,再执行handle,然后再执行postHandle,最后执行afterHandle;preHandle中的返回值为false(拦截)的话,就执行preHandle - 在handle类中有异常的情况下:就执行preHandle <a name="b1b4ac24"></a> ### 3.5.2 拦截器的方法参数说明 (1)前置处理方法,它是在原始方法(业务类中的方法)执行之前执行。java public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(“preHandle”); return true; } - 参数<br /> request:请求对象<br /> response:响应对象<br /> handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装 - 返回值<br /> 返回值为false,被拦截的处理器将不执行 (2)后置处理方法,它是在原始方法执行之后执行。java public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println(“postHandle”); } - 参数<br /> modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整 (3)完成处理方法,它是最后执行的方法。java public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println(“afterCompletion”); } - 参数<br /> ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理 <a name="eae4b36c"></a> ### 3.5.3 拦截器配置项xml <!—设置拦截器的拦截路径,支持通配—> <a name="9fe6d060"></a> ### 3.5.4 多重拦截器的配置 **责任链模式**<br /> 责任链模式是一种行为模式<br /> 特征:<br />沿着一条预先设定的任务链顺序执行,每个节点具有独立的工作任务<br /> 优势:<br />独立性:只关注当前节点的任务,对其他任务直接放行到下一节点<br />隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可<br />灵活性:可以任意修改链路结构动态新增或删减整体链路责任<br />解耦:将动态任务与原始任务解耦<br /> 弊端:<br />链路过长时,处理效率低下<br />可能存在节点上的循环引用现象,造成死循环,导致系统崩溃 <a name="1bc00990"></a> ## 3.6 异常处理 <a name="4287992a"></a> ### 3.6.1 异常处理器 (1)原生的异常处理器:实现 **HandlerExceptionResolver**接口(异常处理器)java @Component public class ExceptionResolver implements HandlerExceptionResolver { public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println(“异常处理器正在执行中”); ModelAndView modelAndView = new ModelAndView(); //定义异常现象出现后,反馈给用户查看的信息 modelAndView.addObject(“msg”,”出错啦! “); //定义异常现象出现后,反馈给用户查看的页面 modelAndView.setViewName(“error.jsp”); return modelAndView; } } 根据异常的种类不同,进行分门别类的管理,返回不同的信息java public class ExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println(“my exception is running ….”+ex); ModelAndView modelAndView = new ModelAndView(); if( ex instanceof NullPointerException){ modelAndView.addObject(“msg”,”空指针异常”); }else if ( ex instanceof ArithmeticException){ modelAndView.addObject(“msg”,”算数运算异常”); }else{ modelAndView.addObject(“msg”,”未知的异常”); } modelAndView.setViewName(“error.jsp”); return modelAndView; } } <a name="8d194263"></a> ### 3.6.2 异常处理器注解开发 (1)使用注解实现异常分类管理 - 注解名称: [@ControllerAdvice ](/ControllerAdvice ) - 类型: 类注解 - 位置:异常处理器类上方 - 作用:设置当前类为异常处理器类 - 范例:java @Component @ControllerAdvice public class ExceptionAdvice { } (2)使用注解实现异常分类管理<br /> 名称: [@ExceptionHandler ](/ExceptionHandler ) <br /> 类型: 方法注解<br /> 位置:异常处理器类中针对指定异常进行处理的方法上方<br /> 作用:设置指定异常的处理方式<br /> 范例:<br /> 说明:处理器方法可以设定多个java @ExceptionHandler(Exception.class) @ResponseBody public String doOtherException(Exception ex){ return “出错啦,请联系管理员! “; } (3)异常处理方案 - 业务异常:<br /> 发送对应消息传递给用户,提醒规范操作 - 系统异常:<br /> 发送固定消息传递给用户,安抚用户<br /> 发送特定消息给运维人员,提醒维护<br /> 记录日志 - 其他异常:<br /> 发送固定消息传递给用户,安抚用户<br /> 发送特定消息给编程人员,提醒维护<br /> 纳入预期范围内<br /> 记录日志 (4)自定义异常 - 自定义异常的格式java //自定义异常继承RuntimeException,覆盖父类所有的构造方法 public class BusinessException extends RuntimeException { public BusinessException() { } public BusinessException(String message) { super(message); } public BusinessException(String message, Throwable cause) { super(message, cause); } public BusinessException(Throwable cause) { super(cause); } public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } } - 异常触发的方式java //在业务代码中对用户传来的请求的参数进行判断,并在不符规范的结果进行制造异常并发出提示信息 if(user.getName().trim().length()<4) { //制造异常(抛出自定义的异常,并传入提示的信息) throw new BusinessException("用户名长度必须在2-4位之间,请重新输入! "); } ``` - 通过自定义异常将所有的异常现象进行分类管理,以统一的格式对外呈现异常消息 ## 3.7 实用技术之文件的上传与下载 (1)文件的上传与下载 - 上传文件的流程图 - MultipartResolver接口 - MultipartResolver接口定义了文件上传过程中的相关操作,并对通用性操作进行了封装 - MultipartResolver接口底层实现类CommonsMultipartResovler - CommonsMultipartResovler并未自主实现文件上传下载对应的功能,而是调用了apache的文件上传下载组件 - 文件上传下载的实现
①在pom文件中导入文件上传的依赖坐标 xml <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> ②创建文件上传的表单 jsp <form action="/fileupload" method="post" enctype="multipart/form-data"> 上传LOGO: <input type="file" name="file"/><br/> <input type="submit" value="上传"/> </form> ④创建springmvc相关的核心配置 xml <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> </bean> ⑤控制层代码 java @RequestMapping(value = "/fileupload") public void fileupload(MultipartFile file){ file.transferTo(new File("file.png")); } ### 3.7.1文件上传下载的注意事项 1. 文件命名问题, 获取上传文件名,并解析文件名与扩展名 2. 文件名过长问题 3. 文件保存路径 4. 重名问题 java @RequestMapping(value = "/fileupload") //参数中定义MultipartFile参数,用于接收页面提交的type=file类型的表单,要求表单名称与参数名相同 public String fileupload(MultipartFile file,MultipartFile file1,MultipartFile file2, HttpServletRequest request) throws IOException { System.out.println("file upload is running ..."+file); // MultipartFile参数中封装了上传的文件的相关信息 // System.out.println(file.getSize());获取文件占磁盘的空间大小 // System.out.println(file.getBytes().length);作用同getSize // System.out.println(file.getContentType());获取文件的类型 // System.out.println(file.getName()); // System.out.println(file.getOriginalFilename());获取文件的上传的原名字 // System.out.println(file.isEmpty());判断文件是否为空 //首先判断是否是空文件,也就是存储空间占用为0的文件 if(!file.isEmpty()){ //如果大小在范围要求内正常处理,否则抛出自定义异常告知用户(未实现) //获取原始上传的文件名,可以作为当前文件的真实名称保存到数据库中备用 String fileName = file.getOriginalFilename(); //设置保存的路径 String realPath = request.getServletContext().getRealPath("/images"); //保存文件的方法,指定保存的位置和文件名即可,通常文件名使用随机生成策略产生,避免文件名冲突问题 file.transferTo(new File(realPath,file.getOriginalFilename())); } //测试一次性上传多个文件 if(!file1.isEmpty()){ String fileName = file1.getOriginalFilename(); //可以根据需要,对不同种类的文件做不同的存储路径的区分,修改对应的保存位置即可 String realPath = request.getServletContext().getRealPath("/images"); file1.transferTo(new File(realPath,file1.getOriginalFilename())); } if(!file2.isEmpty()){ String fileName = file2.getOriginalFilename(); String realPath = request.getServletContext().getRealPath("/images"); file2.transferTo(new File(realPath,file2.getOriginalFilename())); } return "page.jsp"; } ## 3.8 Restful风格配置 (1)Rest - Rest( REpresentational State Transfer) 一种网络资源的访问风格,定义了网络资源的访问方式 - 传统风格访问路径
http://localhost/user/get?id=1
http://localhost/deleteUser?id=1 - Rest风格访问路径
http://localhost/user/1 - Restful是按照Rest风格访问网络资源 - 优点
 隐藏资源的访问行为,通过地址无法得知做的是何种操作
 书写简化 (2)Rest的行为约束 - GET(查询) http://localhost/user/1 GET - POST(保存) http://localhost/user POST - PUT(更新) http://localhost/user PUT - DELETE(删除) http://localhost/user DELETE
注意:上述行为是约定方式,约定不是规范,可以打破,所以称Rest风格,而不是Rest规范 ## 3.9 Restful风格入门开发 java //特别注意:这不是异步请求 //设置rest风格的控制器,该注解相当于@Controller和@ResponseBody //两者的结合体,因此可以同时把数据返回到前端。 @RestController //设置公共访问路径,配合下方访问路径使用 @RequestMapping("/user/") public class UserController { //rest风格访问路径完整书写方式,相当于在地址栏中输入/user/1;这个1就是请求参数 //此注解相当于在类上写了一个@RequestMapping("/user/") @RequestMapping("/user/{id}") //使用@PathVariable注解获取路径上配置的具名变量,该配置可以使用多次 public String restLocation(@PathVariable Integer id){ System.out.println("restful is running ...."); return "success.jsp"; } //rest风格访问路径简化书写方式,配合类注解@RequestMapping使用 @RequestMapping("{id}") public String restLocation2(@PathVariable Integer id){ System.out.println("restful is running ....get:"+id); return "success.jsp"; } //接收GET请求配置方式(查询) @RequestMapping(value = "{id}",method = RequestMethod.GET) //接收GET请求简化配置方式 @GetMapping("{id}") public String get(@PathVariable Integer id){ System.out.println("restful is running ....get:"+id); return "success.jsp"; } //接收POST请求配置方式(保存) @RequestMapping(value = "{id}",method = RequestMethod.POST) //接收POST请求简化配置方式 @PostMapping("{id}") public String post(@PathVariable Integer id){ System.out.println("restful is running ....post:"+id); return "success.jsp"; } //接收PUT请求简化配置方式(修改) @RequestMapping(value = "{id}",method = RequestMethod.PUT) //接收PUT请求简化配置方式 @PutMapping("{id}") public String put(@PathVariable Integer id){ System.out.println("restful is running ....put:"+id); return "success.jsp"; } //接收DELETE请求简化配置方式(删除) @RequestMapping(value = "{id}",method = RequestMethod.DELETE) //接收DELETE请求简化配置方式 @DeleteMapping("{id}") public String delete(@PathVariable Integer id){ System.out.println("restful is running ....delete:"+id); return "success.jsp"; } } - 在web.xml文件中配置拦截器 xml <!--配置拦截器,解析请求中的参数_method,否则无法发起PUT请求与DELETE请求,配合页面表单使用--> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <servlet-name>DispatcherServlet</servlet-name> </filter-mapping> - 针对修改(更新【PUT】)、删除(DELETE)的表单提交的规范  开启SpringMVC对Restful风格的访问支持过滤器,即可通过页面表单提交PUT与DELETE请求
 页面表单使用隐藏域提交请求类型,参数名称固定为method,必须配合提交类型method=post使用 jsp <form action="/user/1" method="post"> <%-- 隐藏表单 --%> <input type="hidden" name="_method" value="PUT"/> <input type="submit"/> </form> - Restful请求路径简化配置方式 java @RestController public class UserController { @RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE) public String restDelete(@PathVariable String id){ System.out.println("restful is running ....delete:"+id); return "success.jsp"; } } ## 3.10 实用技术之表单的校验 (1)认识表单校验的重要性 - 表单校验保障了数据有效性、安全性 (2)表单校验的分类 - 校验位置: - 客户端校验 - 服务端校验 - 校验内容与对应方式: - 格式校验 - 客户端:使用Js技术,利用正则表达式校验 - 服务端:使用校验框架 - 逻辑校验 - 客户端:使用ajax发送要校验的数据,在服务端完成逻辑校验,返回校验结果 - 服务端:接收到完整的请求后,在执行业务操作前,完成逻辑校验 (3)表单校验的规则 - 长度:例如用户名长度,评论字符数量 - 非法字符:例如用户名组成 - 数据格式:例如Email格式、 IP地址格式 - 边界值:例如转账金额上限,年龄上下限 - 重复性:例如用户名是否重复 ### 3.10.1 表单校验的框架 - JSR(Java Specification Requests):Java 规范提案
303:提供bean属性相关校验规则 - JSR规范列表 - 企业应用技术
 Contexts and Dependency Injection for Java (Web Beans 1.0) (JSR 299)
 Dependency Injection for Java 1.0 (JSR 330)@postConstruct, @PreDestroy
 Bean Validation 1.0 (JSR 303)
 Enterprise JavaBeans 3.1 (includes Interceptors 1.1) (JSR 318)
 Java EE Connector Architecture 1.6 (JSR 322)
 Java Persistence 2.0 (JSR 317)
 Common Annotations for the Java Platform 1.1 (JSR 250)
 Java Message Service API 1.1 (JSR 914)
 Java Transaction API (JTA) 1.1 (JSR 907)
 JavaMail 1.4 (JSR 919) - Web应用技术
 Java Servlet 3.0 (JSR 315)
 JavaServer Faces 2.0 (JSR 314)
 JavaServer Pages 2.2/Expression Language 2.2 (JSR 245)
 Standard Tag Library for JavaServer Pages (JSTL) 1.2 (JSR 52)
 Debugging Support for Other Languages 1.0 (JSR 45)
 模块化 (JSR 294)
 Swing应用框架 (JSR 296)
 JavaBeans Activation Framework (JAF) 1.1 (JSR 925)
 Streaming API for XML (StAX) 1.0 (JSR 173) - 管理与安全技术
 Java Authentication Service Provider Interface for Containers (JSR 196)
 Java Authorization Contract for Containers 1.3 (JSR 115)
 Java EE Application Deployment 1.2 (JSR 88)
 J2EE Management 1.1 (JSR 77)
 Java SE中与Java EE有关的规范
 JCache API (JSR 107)
 Java Memory Model (JSR 133)
 Concurrency Utilitie (JSR 166)
 Java API for XML Processing (JAXP) 1.3 (JSR 206)
 Java Database Connectivity 4.0 (JSR 221)
 Java Management Extensions (JMX) 2.0 (JSR 255)
 Java Portlet API (JSR 286) - Web Service技术
 Java Date与Time API (JSR 310)
 Java API for RESTful Web Services (JAX-RS) 1.1 (JSR 311)
 Implementing Enterprise Web Services 1.3 (JSR 109)
 Java API for XML-Based Web Services (JAX-WS) 2.2 (JSR 224)
 Java Architecture for XML Binding (JAXB) 2.2 (JSR 222)
 Web Services Metadata for the Java Platform (JSR 181)
 Java API for XML-Based RPC (JAX-RPC) 1.1 (JSR 101)
 Java APIs for XML Messaging 1.3 (JSR 67)
 Java API for XML Registries (JAXR) 1.0 (JSR 93) - JCP(Java Community Process):Java社区 - Hibernate框架中包含一套独立的校验框架hibernate-validator ### 3.10.2 表单校验入门级操作 (1)相关的注解 - 控制层的注解  名称:@Valid @Validated
 类型:形参注解
 位置:处理器类中的实体类类型的方法形参前方
 作用:设定对当前实体类类型参数进行校验
 范例: java @RequestMapping(value = "/addemployee") public String addEmployee(@Valid Employee employee) { System.out.println(employee); } - javabean上的注解  名称:@NotNull
 类型:属性注解 等
 位置:实体类属性上方
 作用:设定当前属性校验规则
 范例:
每个校验规则所携带的参数不同,根据校验规则进行相应的调整
具体的校验规则查看对应的校验框架进行获取 java public class Employee{ @NotNull(message = "姓名不能为空") private String name;//员工姓名 } - 控制层校验表单 java @RequestMapping(value = "/addemployee") public String addEmployee(@Valid Employee employee, Errors errors, Model model){ System.out.println(employee); if(errors.hasErrors()){ for(FieldError error : errors.getFieldErrors()){ model.addAttribute(error.getField(),error.getDefaultMessage()); } return "addemployee.jsp"; } return "success.jsp"; } - 通过形参Errors获取校验结果数据,通过Model接口将数据封装后传递到页面显示
页面获取后台封装的校验结果信息 jsp <form action="/addemployee" method="post"> 员工姓名:<input type="text" name="name"><span style="color:red">${name}</span><br/> 员工年龄:<input type="text" name="age"><span style="color:red">${age}</span><br/> <input type="submit" value="提交"> </form> ### 3.10.3 多规则的校验 (1)同一个属性可以添加 多个规则 java @NotNull(message = "请输入您的年龄") @Max(value = 60,message = "年龄最大值不允许超过60岁") @Min(value = 18,message = "年龄最小值不允许低于18岁") private Integer age;//员工年龄 - 三种非空规则的区别 spring框架相关的笔记(完结) - 图2 注:为false则没有错误 ### 3.10.4 嵌套校验 (1)相关的注解  名称:@Valid
 类型:属性注解
 位置:实体类中的引用类型属性上方
 作用:设定当前应用类型属性中的属性开启校验
 范例: java public class Employee { //实体类中的引用类型通过标注@Valid注解,设定开启当前引用类型字段中的属性参与校验 @Valid private Address address; }  注意:开启嵌套校验后,被校验对象内部需要添加对应的校验规则 java package com.xiaoha.bean; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; public class Address { @NotBlank(message="省份不能为空") private String province; @NotBlank(message="市不能为空") private String city; } ### 3.10.5 嵌套校验的案例(仅仅展示配置文件) #### ①在pom文件中的导入相关的依赖坐标(注意的是:由于Tomcat插件的版本过低,因此要用本地的tomcat) ```xml <?xml version=”1.0” encoding=”UTF-8”?> 4.0.0 com.xiaoha spring_mvc_validated 1.0-SNAPSHOT war UTF-8 1.8 1.8 javax.servlet javax.servlet-api 3.1.0 provided javax.servlet.jsp javax.servlet.jsp-api 2.3.3 provided org.springframework spring-context 5.1.9.RELEASE org.springframework spring-webmvc 5.1.9.RELEASE org.springframework spring-web 5.1.9.RELEASE junit junit 4.11 test <!—mybatis相关的依赖
—> org.mybatis mybatis 3.5.3 mysql mysql-connector-java 5.1.46 com.alibaba druid 1.1.21 jstl jstl 1.2 com.fasterxml.jackson.core jackson-annotations 2.9.0 com.fasterxml.jackson.core jackson-core 2.9.0 com.fasterxml.jackson.core jackson-databind 2.9.0 org.apache.poi poi 4.0.1 org.apache.poi poi-ooxml 4.0.1 org.springframework spring-jdbc 5.1.9.RELEASE org.mybatis mybatis-spring 1.3.0 javax.validation validation-api 2.0.1.Final org.hibernate hibernate-validator 6.1.0.Final com.github.pagehelper pagehelper 5.1.2 org.apache.tomcat.maven tomcat7-maven-plugin 2.2 80 / <a name="686603be"></a> #### ②在web.xml文件中编写中文乱码的过滤器以及请求拦截分配的映射xml <?xml version=”1.0” encoding=”UTF-8”?> characterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 characterEncodingFilter / DispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-mvc.xml DispatcherServlet / <a name="a2920eaf"></a> #### ③配置springmvc文件中相关的注解驱动xml <?xml version=”1.0” encoding=”UTF-8”?> text/html;charset=UTF-8 application/json;charset=UTF-8 /;charset=UTF-8 <a name="e6d76b13"></a> ### 3.10.6 分组校验 - 同一个模块,根据执行的业务不同,需要校验的属性会有不同 - 新增用户 - 修改用户 - 对不同种类的属性进行分组,在校验时可以指定参与校验的字段所属的组类别 - 定义组(通用) - 为属性设置所属组,可以设置多个 - 开启组校验java public interface GroupOne { } ```java public String addEmployee(@Validated({GroupOne.class}) Employee employee){ } # 四、SSM整合 (1)整体分析 ①SSM(Spring+SpringMVC+MyBatis) - Spring - 框架基础 - MyBatis - mysql+druid+pagehelper(分页插件) - Spring整合MyBatis - junit测试业务层接口 - SpringMVC - rest风格(postman测试请求结果) - 数据封装json(jackson) - Spring整合SpringMVC - Controller调用Service - 其他 - 表现层数据封装 - 自定义异常 ② 最重要的5个步骤 1. Spring 2. MyBatis 3. Spring整合MyBatis 4. SpringMVC 5. Spring整合SpringMVC ## 4.1案例实现步骤 - 基本的思路 - maven工程的项目结构的搭建 - spring整合mybatis - 整合junit - spring整合springmvc - 表现层数据的封装 - 自定义异常 - 自定义异常兼容消息 ### 4.1.1 分步骤一:项目基础结构的搭建 - 创建项目,组织项目结构,创建包 - 创建表与实体类 - 创建三层架构对应的模块、接口与实体类,建立关联关系 - 数据层接口(代理自动创建实现类) - 业务层接口+业务层实现类 - 表现层类 ### 4.1.2 分步骤二:三层的业务代码的实现 #### ①dao层代码实现 java package com.xiaoha.dao; import com.github.pagehelper.PageInfo; import com.xiaoha.domain.User; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; //@Repository public interface UserDao { /** * 添加信息 * @param user * @return */ public abstract boolean save(User user); /** * 根据id删除数据 * @param uuid * @return */ public abstract boolean delete(Integer uuid); /** * 修改数据 * @param user * @return */ public abstract boolean update(User user); /** * 查询全部 * @return */ public abstract List<User> findAll(); /** * 根据id查询单条数据 * @param uuid * @return */ public abstract User findById(Integer uuid); /** * 根据用户名与密码查询单条数据 * @param username * @param password * @return */ public abstract User findByUsernameAndPassword(@Param("userName") String username,@Param("password") String password); } #### ②Service层代码实现 java //Service的接口 package com.xiaoha.service; import com.github.pagehelper.PageInfo; import com.xiaoha.domain.User; import org.springframework.transaction.annotation.Transactional; //标记开启事务的注解,参数开启只读 @Transactional(readOnly=true) public interface UserService { /** * 添加信息 * @param user * @return */ //保存不能为只读,因此关闭只读模式 @Transactional(readOnly=false) public abstract boolean save(User user); /** * 根据id删除数据 * @param uuid * @return */ //删除不能为只读,因此关闭只读模式 @Transactional(readOnly=false) public abstract boolean delete(Integer uuid); /** * 修改数据 * @param user * @return */ //修改不能为只读,因此关闭支付模式 @Transactional(readOnly = false) public abstract boolean update(User user); /** * 查询全部 * @param page * @param size * @return */ public abstract PageInfo<User> findAll(int page, int size); /** * 根据id查询单条数据 * @param uuid * @return */ public abstract User findById(Integer uuid); /** * 根据用户名与密码查询单条数据 * @param username * @param password * @return */ public abstract User login(String username,String password); } package com.xiaoha.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.xiaoha.dao.UserDao; import com.xiaoha.domain.User; import com.xiaoha.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; //spring的bean注解 @Service public class UserServiceImpl implements UserService { //自动填装值IoC容器 @Autowired private UserDao userDao; //添加数据 @Override public boolean save(User user) { boolean result = userDao.save(user); return result; } //删除数据 @Override public boolean delete(Integer uuid) { boolean result = userDao.delete(uuid); return result; } //修改数据 @Override public boolean update(User user) { boolean result = userDao.update(user); return result; } //分页查询(查询全部) @Override public PageInfo<User> findAll(int page, int size) { PageHelper.startPage(page,size); List<User> all = userDao.findAll(); PageInfo<User> result = new PageInfo<>(all); return result; } //根据id查询 @Override public User findById(Integer uuid) { User result = userDao.findById(uuid); return result; } //登录查询 @Override public User login(String username, String password) { User result = userDao.findByUsernameAndPassword(username,password); return result; } } #### ④Controller层代码实现 java package com.xiaoha.controller; import com.github.pagehelper.PageInfo; import com.xiaoha.controller.nrom.Code; import com.xiaoha.controller.nrom.Result; import com.xiaoha.domain.User; import com.xiaoha.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; //标记rest风格的控制器,此注解相当于Controller与ResponseBody(响应数据给前端的注解)两个 @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; // 如果请求参数为多个 则是以表单形式提交,封装成javabean类型 // 因此注解就不用参数 //添加保存数据,相关的地址访问: //localhost/user?userName=司马懿&password=5588&realName=司马仲达 //&gender=1&birthday=179/12/02 @PostMapping public Result save(User user){ //System.out.println("user"+"..."+user); boolean flag= userService.save(user); return new Result(flag? Code.SAVE_SUCCEED:Code.SAVE_ERROR); } //根据id查询单条数据,相关访问地址:localhost/user/1 @GetMapping("{uuid}") public Result findById( @PathVariable Integer uuid){ User result = userService.findById(uuid); //System.out.println("get"+":"+uuid); return new Result(result,result!=null?Code.LOOK_SUCCEED:Code.LOOK_ERROR); } //查询所有的信息,相关访问地址:localhost/user/1/5 @GetMapping("/{page}/{size}") public Result finAll(@PathVariable Integer page ,@PathVariable Integer size){ PageInfo<User> result = userService.findAll(page,size); //System.out.println("page"+","+page+" "+"size"+","+size); return new Result(result,result!=null?Code.LOOK_SUCCEED:Code.LOOK_ERROR); } //根据id删除数据,相关访问地址:localhost/user/21 @DeleteMapping("/{uuid}") public Result delete(@PathVariable Integer uuid){ boolean flag = userService.delete(uuid); //System.out.println("uuid"+uuid); return new Result(flag? Code.DELETE_SUCCEED:Code.DELETE_ERROR); } //修改数据,相关访问地址:localhost/user?userName=司马懿kk&password=55883&realName=司马仲达dd&gender=1&birthday=179/12/02&uuid=20 @PutMapping public Result update( User user){ boolean flag = userService.update(user); // System.out.println("Putuser"+user); return new Result(flag? Code.UPDATE_SUCCEED:Code.UPDATE_ERROR); } //登录,为避免跟添加功能产生冲突,因此添加一个子路径 //进行区分 ,相关访问地址:localhost/user/login/?userName=张良&password=6699 @PostMapping("/login/") public Result login( String userName, String password){ User result = userService.login(userName,password); //System.out.println("userName:"+userName+"password"+password); return new Result(result,result!=null?Code.LOOK_SUCCEED:Code.LOOK_ERROR); } } #### ⑤Controller层相关的结果处理的设计类——结果封装类 java package com.xiaoha.controller.nrom; public class Result { //结果数据 private Object data; //响应的消息 private String message; //响应的代码 private Integer code; public Object getData() { return data; } public Result(Object data, Integer code) { this.data = data; this.code = code; } public Result(Integer code) { this.code = code; } } #### ⑥Controller层相关的结果处理的设计类——提示代码封装类 java package com.xiaoha.controller.nrom; public class Code { //操作类型的提示代码 //①操作成功的代码 public static final Integer SAVE_SUCCEED=20011; public static final Integer UPDATE_SUCCEED=20021; public static final Integer DELETE_SUCCEED=20031; public static final Integer LOOK_SUCCEED=20041; //②操作失败的代码 public static final Integer SAVE_ERROR=20010; public static final Integer UPDATE_ERROR=20020; public static final Integer DELETE_ERROR=20030; public static final Integer LOOK_ERROR=20040; } #### ⑦controller层自定义异常信息 - 设定自定义异常,封装程序执行过程中出现的问题,便于表现层进行统一的异常拦截并进行处理 - BusinessException - SystemException - 代码实现 java public class BusinessException extends RuntimeException { //自定义异常中封装对应的错误编码,用于异常处理时获取对应的操作编码 private Integer code; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public BusinessException(Integer code) { this.code = code; } public BusinessException(String message, Integer code) { super(message); this.code = code; } public BusinessException(String message, Throwable cause,Integer code) { super(message, cause); this.code = code; } public BusinessException(Throwable cause,Integer code) { super(cause); this.code = code; } public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,Integer code) { super(message, cause, enableSuppression, writableStackTrace); this.code = code; } } #### ⑧controller层返回信息兼容错误信息的类 java @Component //spring bean注解 @ControllerAdvice //增强拦截注解 public class ProjectExceptionAdivce { @ExceptionHandler(BusinessException.class) //异常处理拦截执行注解,拦截自定义的异常类 @ResponseBody //对出现异常的情况进行拦截,并将其处理成统一的页面数据结果格式 public Result doBusinessException(BusinessException e){ //返回自定义的结果处理对象,参数为执行编码,和异常信息 return new Result(e.getCode(),e.getMessage()); } } ### 4.1.3 分步骤三:相关的核心配置文件的配置 #### ①pom.xml文件 xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xiaoha.spring_ssm</groupId> <artifactId>spring_ssm</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <!-- servlet3.0 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--jsp--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <!-- spring相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!-- spring mvc相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!-- spring相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--单元测试相关依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--spring整合Junit相关的依赖坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--mybatis相关的依赖_--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <!--mysql相关的依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!--druid数据源相关的依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!--jackson相关依赖--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> <!--POI相关的依赖--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!--导入校验的jsr303规范--> <!--<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>--> <!--导入校验框架实现技术--> <!-- <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.0.Final</version> </dependency>--> <!--分页插件的依赖坐标--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.2</version> </dependency> </dependencies> <build> <plugins> <!--tomcat插件--> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>80</port> <path>/</path> </configuration> <!--<groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat8-maven-plugin</artifactId> <version>2.2</version>--> </plugin> </plugins> </build> </project> #### ②spring相关的核心配置 ```xml <?xml version=”1.0” encoding=”UTF-8”?> text/html;charset=UTF-8 application/json;charset=UTF-8 /;charset=UTF-8

<?xml version=”1.0” encoding=”UTF-8”?>

  1. <!--开启注解式事务-->
  2. <tx:annotation-driven transaction-manager="txManager"/>
  3. <!--加载properties文件-->
  4. <context:property-placeholder location="classpath*:data.properties"/>
  5. <!--数据源-->
  6. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
  7. <property name="driverClassName" value="${jdbc.driver}"/>
  8. <property name="url" value="${jdbc.url}"/>
  9. <property name="username" value="${jdbc.username}"/>
  10. <property name="password" value="${jdbc.password}"/>
  11. </bean>
  12. <!--整合mybatis到spring中-->
  13. <bean class="org.mybatis.spring.SqlSessionFactoryBean">
  14. <property name="dataSource" ref="dataSource"/>
  15. <property name="typeAliasesPackage" value="com.xiaoha.domain"/>
  16. <!--分页插件-->
  17. <property name="plugins">
  18. <array>
  19. <bean class="com.github.pagehelper.PageInterceptor">
  20. <property name="properties">
  21. <props>
  22. <prop key="helperDialect">mysql</prop>
  23. <prop key="reasonable">true</prop>
  24. </props>
  25. </property>
  26. </bean>
  27. </array>
  28. </property>
  29. </bean>
  30. <!--映射扫描-->
  31. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  32. <property name="basePackage" value="com.xiaoha.dao"/>
  33. </bean>
  34. <!--事务管理器-->
  35. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  36. <property name="dataSource" ref="dataSource"/>
  37. </bean>

  1. <a name="ebce5969"></a>
  2. #### ③web相关的核心配置
  3. ```xml
  4. <?xml version="1.0" encoding="UTF-8"?>
  5. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  6. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  7. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  8. version="4.0">
  9. <!--配置解决中文乱码的过滤器-->
  10. <filter>
  11. <filter-name>CharacterEncodingFilter</filter-name>
  12. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  13. <!--配置初始参数-->
  14. <init-param>
  15. <param-name>encoding</param-name>
  16. <param-value>UTF-8</param-value>
  17. </init-param>
  18. </filter>
  19. <filter-mapping>
  20. <filter-name>CharacterEncodingFilter</filter-name>
  21. <url-pattern>/*</url-pattern>
  22. </filter-mapping>
  23. <!--配置拦截器,解析请求中的参数_method,
  24. 否则无法发起PUT请求与DELETE请求,配合页面表单使用-->
  25. <filter>
  26. <filter-name>HiddenHttpMethodFilter</filter-name>
  27. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  28. </filter>
  29. <filter-mapping>
  30. <filter-name>HiddenHttpMethodFilter</filter-name>
  31. <servlet-name>DispatcherServlet</servlet-name>
  32. </filter-mapping>
  33. <!--配置mvc请求拦截分配的标签-->
  34. <servlet>
  35. <servlet-name>DispatcherServlet</servlet-name>
  36. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  37. <!--配置初始参数-->
  38. <init-param>
  39. <param-name>contextConfigLocation</param-name>
  40. <param-value>classpath:spring-mvc.xml</param-value>
  41. </init-param>
  42. </servlet>
  43. <servlet-mapping>
  44. <servlet-name>DispatcherServlet</servlet-name>
  45. <url-pattern>/</url-pattern>
  46. </servlet-mapping>
  47. <!--spring配置文件-->
  48. <context-param>
  49. <param-name>contextConfigLocation</param-name>
  50. <param-value>classpath:applicationContext.xml</param-value>
  51. </context-param>
  52. <!--spring的监听器 其目的是告诉tomcat使用的是spring-->
  53. <listener>
  54. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  55. </listener>
  56. </web-app>

4.14 单元测试相关的代码实现

  1. package com.xiaoha.service;
  2. import com.github.pagehelper.PageInfo;
  3. import com.xiaoha.dao.UserDao;
  4. import com.xiaoha.domain.User;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10. import java.text.ParseException;
  11. import java.text.SimpleDateFormat;
  12. import java.util.Date;
  13. import java.util.List;
  14. //标注spring单元测试的注解
  15. @RunWith(SpringJUnit4ClassRunner.class)
  16. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  17. public class UserServiceTest {
  18. //测哪一层就导入哪一层的接口
  19. @Autowired
  20. private UserService userService;
  21. @Test
  22. public void testSave(){
  23. User user = new User();
  24. user.setUserName("孙权");
  25. user.setPassword("9876");
  26. user.setRealName("孙仲谋");
  27. user.setGender(1);
  28. String dateStr = "182-12-03";
  29. SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");
  30. try {
  31. Date date = sdf.parse(dateStr);
  32. user.setBirthday(date);
  33. } catch (ParseException e) {
  34. e.printStackTrace();
  35. }
  36. userService.save(user);
  37. /*System.out.println("haha");*/
  38. }
  39. @Test
  40. public void testDelete(){
  41. userService.delete(18);
  42. }
  43. @Test
  44. public void testUpdate(){
  45. User user = new User();
  46. user.setUuid(17);
  47. user.setUserName("张良");
  48. user.setPassword("6699");
  49. user.setRealName("张子房");
  50. user.setGender(1);
  51. String dateStr = "149-02-03";
  52. SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");
  53. try {
  54. Date date = sdf.parse(dateStr);
  55. user.setBirthday(date);
  56. } catch (ParseException e) {
  57. e.printStackTrace();
  58. }
  59. userService.update(user);
  60. }
  61. @Test
  62. public void testFindAll(){
  63. PageInfo<User>info = userService.findAll(2,5);
  64. List<User> results=info.getList();
  65. for (User result : results) {
  66. System.out.println(result);
  67. }
  68. }
  69. @Test
  70. public void testFindById(){
  71. User result=userService.findById(10);
  72. System.out.println(result);
  73. }
  74. @Test
  75. public void testLogin(){
  76. User result = userService.login("张良","6699");
  77. System.out.println(result);
  78. }
  79. }

特别注意:其包结构要与源代码中保持一致