1. Spring
1.1 Spring简介
Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IoC
(Inverse of Control:控制反转)和AOP
(Aspect oriented Programming:面向切面编程)为内核。它提供了展现层SpringMVC和持久层Spring JDBCTemplate以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。
Spring的优点:
- 方便解耦,简化开发:通过Spring提供的loC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
- AOP编程的支持:通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现。
- 声明式事务的支持:可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。
- 方便程序的测试:可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
- 方便集成各种优秀框架:Spring对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的支持。
- 降低Java EE API的使用难度:Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
Spring体系结构
:
1.2 Spring配置文件
- Bean标签基本配置
Bean标签用于配置对象交由Spring来创建,默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。基本属性:
(1)id
:Bean实例在Spring容器中的唯一标识
(2)class
:Bean的全限定名称(全包名)
(3)scope
:Bean标签对象的作用范围
(4)init-method
:指定类中的初始化方法名称
(5)destory-method
:指定类中的销毁方法名称
- Bean实例化三种方式
(1)无参构造方法实例化:默认
(2)工厂静态方法实例化:class属性指定含有静态实例化方法的类的路径,再通过factory-method属性指定静态方法。
(3)工厂实例方法实例化:先用无参构造创建工厂对象,再通过factory-bean和factory-method属性分别指定对应的工厂Bean的id和方法。 - 依赖注入
依赖注入(Dependency Injection):它是Spring框架核心IOC的具体实现。在编写程序时,通过控制反转,把对象的创建交给了Spring,IOC解耦只是降低依赖关系,但不会消除,如业务层仍会调用持久层的方法,Spring框架会把持久层对象传入业务层,而不用我们自己去获取。
(1)set方法:在业务层创建持久层对象,并设置set方法。方法一:通过在业务层Bean中添加property标签,并用name和ref属性分别指向set方法名(不包含set,且首字母小写)和持久层Bean的id。方法二:在xml配置文件中添加p命名空间:xmlns:p=“http://www.springframework.org/schema/p”,然后直接在业务层Bean中使用p:属性指定持久层Bean的id即可。
(2)有参构造:在业务层创建持久层对象,并定义有参构造。通过在业务层Bean中添加constructor-arg标签,并用name和ref属性分别指向有参构造的形参名和持久层Bean的id。
注入数据的三种数据类型:
(1)普通数据类型:在持久层,set方法(property标签name和value属性),有参构造类似用constructor-arg标签。
(2)引用数据类型
(3)集合数据类型:set方法:list标签配合value标签实现List集合;map标签配合entry标签(属性key,value,value-ref)实现Map集合;props标签配合prop(属性key,内部写值)实现Properties集合。 - 分模块开发
在主配置文件appliactionContext.xml中通过import标签的resource属性对其他分配置文件进行加载。
1.3 Spring有关的API
- ApplicationContext的实现类
(1)ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)。
(2)FileSystemXmlApplicationContext:从磁盘路径上加载配置文件。
(3)AnnotationConfigApplicationContext:当使用注解配置容器对象时,需要使用此类来创建Spring容器,它用来读取注解。 - getBean()方法
(1)Object getBean(String name):通过Bean的唯一id获取唯一的实例对象,需要强制转换。
(2)T getBean(Class type):通过字节码文件获取实例对象,不用强转,但一个类可能有多个Bean标签(这种情况会报错)。
1.4 Spring配置数据源
数据源(连接池)是存放数据库连接的一个容器,数据源(连接池)是提高程序性能而出现的;事先实例化数据源,初始化部分连接资源;使用连接资源时从数据源中获取;使用完毕后将连接资源归还给数据源。常用的数据源连接池:Druid,C3P0,DBCP,BoneCP等。
- 数据源开发步骤
(1)导入数据源的坐标和数据库驱动坐标:mysql-connector-java,c3p0,druid。
(2)创建数据源对象。
(3)设置数据源的基本连接数据。
(4)使用数据源获取连接资源和归还连接资源。
(5)抽取jdbc.properties配置文件,将可能会更改的数据库等信息抽取到resources中。(1) 使用c3p0数据源 ComboPooledDataSource dataSource = new ComboPooledDataSource(); //创建c3p0数据源对象 dataSource.setDriverClass("com.mysql.jdbc.Driver"); //设置驱动 dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); //设置连接的url(test为数据库名) dataSource.setUser("root"); //设置用户名 dataSource.setPassword("123456"); //设置连接密码 Connection connection = dataSource.getConnection(); //获取连接资源 //使用资源 connection.close(); //归还连接资源 (2) 使用druid数据源 DruidDataSource dataSource = new DruidDataSource();//创建druid数据源对象 dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //设置驱动 dataSource.setUrl("jdbc:mysql://localhost:3306/test"); //设置连接的url(test为数据库名) dataSource.setUsername("root"); //设置用户名 dataSource.setPassword("123456"); //设置连接密码 DruidPooledConnection connection = dataSource.getConnection();//获取连接资源 //使用资源 connection.close(); //归还连接资源 (3) 抽取为jdbc.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=123456 ResourceBundle rb = ResourceBundle.getBundle("jdbc"); rb.getString("jdbc.driver"); //引用
- Spring配置数据源
将DataSource的创建去交由Spring容器完成(由于数据源对象都用的set方法设置的连接数据,所以可以将该数据源对象封装成Bean,再配合标签property设置具体的值),通过applicationContext.xml加载jdbc.properties配置文件获得连接信息,以c3p0数据源为例。(1) 在applicationContext.xml中引入命名空间和约束路径 xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd (2) 由Spring加载properties文件并配置数据源Bean <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
1.5 Spring注解开发
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。<context:component-scan base-package="包的路径"/>
- Spring原始注解:主要是替代Bean的配置,如下所示:
(1)@Component、@Controller、@Service、@Repository作用都是实例化Bean,不过后三者可以根据语义就知道属于哪一层。
(2)@Autowired会根据数据类型从Spring容器中进行匹配;@Qualifier(“id值”)配合@Autowired则会按照id值从容器中进行匹配;@Resource(name=“id值”)则结合了前两个注解按照id进行依赖注入。用注解实现字段的依赖注入可以不用写set方法,xml配置使用set方法进行依赖注入则必须定义set方法。
(3)@Value(“${配置文件中的名称}”):可以引入配置文件中的值,前提在配置文件中已加载properties文件。
(4)@Scope(“singleton”):设置标签的作用范围。
(5)@PostConstruct和@PreDestroy可以在方法上注解,标明是初始化方法还是销毁方法。
- Spring新注解:原始注解还不能全部替代xml配置文件,如非自定义的Bean的配置;加载properties文件的配置;组件扫描的配置;引入其他文件等。加上新注解就可以实现全注解开发了,可以配合AnnotationConfigApplicationContext实现类来创建容器对象。
1.6 Spring集成Junit
让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它;将需要进行测试的Bean直接在测试类中进行注入。
(1)导入Spring集成Junit的坐标:spring-test。
(2)使用@RunWith(SpringJUnit4ClassRunner.class)注解替换原来的运行期。
(3)使用@ContextConfiguration(“classpath:applicationContext.xml”)指定配置文件或@ContextConfiguration(classes = { 配置类.class })指定配置类。
(4)使用@Autowired注入需要测试的对象。
(5)使用@Test创建测试方法进行测试。
1.7 Spring集成Web环境
添加javax.servlet-api和javax.servlet.jsp-api坐标,在web层定义继承HttpServlet的Servlet类并重写doGet方法,在web.xml中配置对Servlet的引用。
<servlet>
<servlet-name>Servlet名称</servlet-name>
<servlet-class>Servlet的全限定包名</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet名称</servlet-name>
<url-pattern>/url</url-pattern>
</servlet-mapping>
ContextLoaderListener
Spring提供了一个监听器ContextLoaderListener实现加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下位对象。前提在pom中导入spring-web坐标。
(1) 在web.xml中配置ContextLoaderListener监听器,同时指定全局加载的Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>
(2) 使用WebApplicationContextUtils获取应用上下文对象ApplicationContext,在Servlet类重写的doGet()方法中
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
//使用app来创建Bean实例化对象
1.8 Spring JdbcTemplate
Spring JdbcTemplate是Spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。Spring框架为我们提供了很多的操作模板类。如:操作关系型数据库的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate。
- JdbcTemplate开发步骤
(1)导入spring-jdbc、spring-tx、mysql-connector-java、c3p0坐标
(2)创建数据库表和实体类
(3)创建JdbcTemplate对象,并设置数据源
(4)执行数据库操作 - Spring产生JdbcTemplate对象
将JdbcTemplate和其注入的DataSource都通过Bean注入。<!-- JdbcTemplate模板对象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean>
- JdbcTemplate查询
List<Account> list = jdbcTemplate.query("select * from 表名", new BeanPropertyRowMapper<>(实体类.class)); //查询多个 实体类 pojo = jdbcTemplate.queryForObject("select * from 表名 where name='Tom'", new BeanPropertyRowMapper<>(实体类.class));//查询一个 long count = jdbcTemplate.queryForObject("select count(*) from 表名", Long.class); //聚合函数
1.9 Spring的AOP
AOP(Aspect Oriented Programming)面向切面编程
,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- AOP的作用和优势
(1)作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强。
(2)优势:减少重复代码,提高开发效率,并且便于维护。 - AOP的底层实现
AOP的底层是通过Spring提供的的动态代理技术
实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强。
(1)JDK代理:基于接口的动态代理技术,JavaSE中的动态代理。
(2)cglib代理:基于父类的动态代理技术,已经封装在Spring核心中,(1. 创建Enhancer增强器;2. 增强器设置父类(目标对象);3. 设置回调(在这里进行功能增强的插入);4. 创建代理对象(目标对象类型,多态)) - AOP的相关概念
(1)Target(目标对象):代理的目标对象。
(2)Proxy(代理):一个类被AOP织入增前后,就产生一个结果代理类。
(3)Joinpoint(连接点):所谓连接点是指那些被拦截到的点(即目标对象可以增强的方法)。在Spring中,这些点指的是方法(只支持方法类型的连接点)。
(4)Pointcut
(切入点):指要对那些Joinpoint进行拦截定义(即目标对象要在哪个方法中增强的方法)。
(5)Advice
(通知/增强):指拦截到Joinpoint之后要做的事情(增强方法的定义)。
(6)Aspect
(切面):切入点和通知的结合。
(7)Weaving
(织入):把增强应用到目标对象来创建新的代理对象的过程(Spring采用动态代理织入,而AspectJ采用编译期织入和类装载织入)。 - AOP开发事项和要点
(1)编写的内容:核心业务代码(目标类中的目标方法);切面类(增强功能的方法);配置文件中配置织入关系(即将哪些通知与那些连接点进行结合)。
(2)AOP技术实现的内容:Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
(3)AOP底层使用哪种代理方法:在Spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。 - 基于XML的AOP开发
(1)导入AOP相关坐标,spring-context(虽有aop但不如aspectj更轻)、aspectjweaver。
(2)创建目标接口和目标类(内部有切点)。
(3)创建切面类(内部有增强方法)。
(4)把目标类和切面类的对象创建权交给Spring(即创建Bean标签对象)。
(5)在applicationContext.xml中配置织入关系
(6)接口接收目标对象即代理对象,调用方法。<!-- 配置织入:告诉Spring框架哪些方法(切点)需要进行哪些增强(前置、后置...) --> <aop:config> <!-- 声明切面 --> <aop:aspect ref="切面类的Bean的id"> <!-- 切面:切点+通知 --> <aop:before method="增强的方法名(通知)" pointcut="execution(目标要在哪个方法里增强的方法(切点))"/> <aop:after method="后置增强的方法名" pointcut="类似"/> </aop:aspect> </aop:config>
切点表达式的写法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
(1)访问修饰符可以省略。
(2)返回值类型、包名、类名、方法名可以使用星号*代表任意。
(3)包名和类名之间一个点.代表当前包下的类,两个点…代表当前包及其子包下的类。
(4)参数列表可以使用两个点…表示任意个数,任意类型的参数列表。
切点表达式的抽取: 通过使用aop:pointcut标签,指定其id和expression(共有的切点表达式),在增强中通过pointcut-ref属性进行引用。
通知的种类:
- 基于注解的AOP开发
(1)创建目标接口和目标类(内部有切点)。
(2)创建切面类(内部有增强方法)。
(3)把目标类和切面类的对象创建权交给Spring(使用@Component注解)。
(4)在切面类中使用注解配置织入关系(在切面类上使用@Aspect注解表明是切面类,在方法上注解通知类型和切点表达式)。
切点表达式的抽取: 在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在其他通知注解中使用该方法名()就可代替切点表达式。
(5)在配置文件中开启组件扫描和AOP的自动代理。<!-- 开启组件扫描 --> <context:component-scan base-package="扫描的包名"/> <!-- AOP自动代理 --> <aop:aspectj-autoproxy/>
1.10 Spring的事务控制
- 编程式事务控制
(1)PlatformTransactionManager接口是Spring的事务管理器,提供了常用的操作事务的方法。不同的Dao层技术有不同的实现类,如当Dao层技术是jdbc或mybatis时:org.springframework.jdbc.datasource.DataSourceTransactionManager;当Dao层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager。
(2)TransactionDefinition是事务的定义信息对象。
事务的传播行为:
(3)TransactionStatus接口提供事务具体的运行状态
- 基于XML的声明式事务控制
Spring声明式事务:采用声明的方式来处理事务。Spring声明式事务控制底层就是AOP
。优点:事务管理不侵入开发的组件(事务管理属于系统层面的服务,而不是业务逻辑的一部分,解耦,AOP思想:业务逻辑是切点,事务管理是通知);若不需要事务管理,只需再设定文件上修改(无需改变代码重新编译,更方便维护)。<!-- 配置事务平台管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 通知:事务的增强 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 设置事务的属性信息 --> <tx:attributes> <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/> </tx:attributes> </tx:advice> <!-- 配置事务AOP的织入 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="事务切点的切点表达式"/> </aop:config>
- 基于注解的声明式事务控制
通过@Transactional注解在类或方法上指定对应方法的事务控制方式,该注解有isolation、propagation、timeout、readOnly等属性控制事务的传播行为。<!-- 配置事务平台管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 事务的注解驱动 --> <tx:annotation-driven transaction-manager="transactionManager"/>
2. SpringMVC
SpringMVC是一种基于Java实现的MVC设计模式的请求读懂类型的轻量级Web框架。它通过一套注解,让一个简单的Java类称为处理请求的控制器,而无须实现任何接口,同时还支持RESTful编程风格的请求。
2.1 SpringMVC简单使用
用SpringMVC实现客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。
(1)导入spring-webmvc坐标
(2)配置SpringMVC核心控制器DispatcherServlet(在web.xml中进行配置)
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(3)创建Controller类和视图页面,在SpringMVC配置文件中开启注解扫描
<context:component-scan base-package="controller全包名"/>
<!-- 配置内部资源视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="前缀"></property>
<property name="suffix" value="后缀"></property>
</bean>
(4)使用注解配置Controller类中业务方法的映射地址(@Controller和@RequetMapping("/url")
)
@RequetMapping:用于建立请求URL和处理请求方法之间的对应关系。
位置:
类上:请求URL的第一级访问目录,此处不写就相当于应用的根目录。
方法上:请求URL的第二级访问目录,与类上的一级目录一起组成访问虚拟路径。
属性:
value:指定请求的URL。只有一个属性时可默认不指定属性名。
method:指定请求的方式。
params:指定限制请求参数的条件(即限制请求的参数必须包含哪些参数)。
(5)客户端发起请求测试
2.2 SpringMVC执行流程
(1)用户发送请求至前端控制器DispatcherServlet。(2)DispatcherServlet收到请求调用HandlerMapping处理器映射器。
(3)处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
(4)DispatcherServlet调用HandlerAdapter处理器适配器。
(5)HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
(6)Controller执行完成返回ModelAndView。
(7)HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
(8)DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
(9)ViewReslover解析后返回具体View。
(10)DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
(11)DispatcherServlet响应用户。
2.3 SpringMVC数据响应
SpringMVC的数据响应方式
(1)页面跳转
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。
转发(默认):forward:url
重定向:redirect:url
通过ModelAndView对象返回:可以通过add添加数据,set设置视图等。
(2)回写数据
直接返回字符串:通过@ResponseBody
注解告知SpringMVC不跳转页面而是直接数据响应返回字符串。比如返回JavaBean对象的json字符串,可以先导入jackson-core、jackson-databind、jackson-annotations坐标,再创建ObjectMapper对象,通过它的writeValueAsString方法将对象转换为json字符串。
返回对象或集合:返回类型直接是对象或集合,自动会将它们准换为JSON字符串。
<!-- 配置处理器映射器(自动将对象转换为JSON字符串) -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
<!-- mvc的注解驱动,引入mvc命名空间,默认底层就会继承jackson进行对象或集合的json格式字符串的转换 -->
<mvc:annotation-driven/>
2.4 SpringMVC获取请求数据
-
SpringMVC 接收参数类型
(1) 基本类型
在Controller中的业务方法的参数名称与请求参数的名称一致,参数值会自动映射匹配。
(2)POJO类型
在Controller中的业务方法的POJO参数的属性名与请求参数的名称一致,参数值会自动映射匹配。
(3) 数据类型
在Controller中的业务方法数组名称与请求参数的名称一致,参数值会自动映射匹配。
(4) 集合类型
获取集合参数时(如列表数据),要将集合参数包装到一个POJO中即可。
当使用ajax或axios提交时,可以指定contentType为json形式,那么在Controller中的业务的方法参数位置使用@RequestBody
注解就可以直接接收集合数据。 -
SpringMVC 静态资源的访问(如js脚本,img图片等,在SpringMVC的配置文件中设置)
<!-- 静态资源的访问 --> <mvc:default-servlet-handler/>
-
SpringMVC 请求数据乱码(过滤器进行编码过滤,在web.xml中进行配置)
<!-- 配置全局过滤器解决乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
参数绑定注解
@RequestParam
当请求的参数名称与Controller的业务方法参数名称不一致时,可以通过@RequestParam(“请求的参数名”)注解在形参的前边进行绑定。如@RequestParam(“userName”) String name。
(1)value:请求的参数名称(若只有一个参数可以不写)。
(2)required:指定请求的参数是否必须包括,默认是true。
(3)defaultValue:当没有指定请求参数时,则使用指定的默认值赋值。 -
Restful风格请求
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用url+请求方式表示请求目的,HTTP协议里面四个表示操作方式的动词:GET(获取资源)、POST(新建资源)、PUT(更新资源)、DELETE(删除资源)。如对于url地址/user/1中的1就是要获得的请求参数,在SpringMVC中可以使用占位符进行参数绑定,在Controller的映射url注解中使用/user/{id},占位符{id}对应的就是1的值,再业务方法中通过在形参前边使用@PathVariable
注解来与占位符匹配,形参就可以随便起名了。 -
自定义类型转换器
SpringMVC默认已经提供了一些常用的类型转换器,如会根据形参的类型自动将字符串转换为int型等。但不是所有的数据类型都提供了类型转换器,因此需要自定义转换器。
(1)定义转换器类实现Converter接口
(2)在配置文件中声明转换器<!-- 声明转换器 --> <bean id="ConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="转换器类的全限定包名"></bean> </list> </property> </bean>
(3)在< annotation-driven conversion-service=“ConversionService” >中引用转换器
-
获取Servlet相关API
在Controller业务层的方法中的形参,方法调用者是SpringMVC框架,且SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,因此会自动识别那些ServletAPI对象:HttpServletRequest、HttpServletResponse、HttpSession等(前提是导入javax-servlet坐标)。 -
获取请求头
(1)@RequestHeader
:获取请求头信息。value:请求头名称;required:是否必须携带此请求头。
(2)@CookieValue
:获取指定Cookie的值。属性一样有value和required。 -
文件上传
(1) 文件上传客户端三要素
表单项type=“file”
表单的提交方式是post
表单的enctype属性是多部分表单形式,即enctype=“mulitipart/form-data”
(2)单文件上传
导入commons-fileupload和commons-io坐标
配置文件上传解析器<!-- 配置文件上传解析器,还可以设置更多的配置 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 上传文件最大总大小 --> <property name="maxUploadSize" value="5242800"/> <!-- 上传单个文件的最大大小 --> <property name="maxUploadSizePerFile" value="5242800"/> <!-- 上传文件的编码类型 --> <property name="defaultEncoding" value="UTF-8"/> </bean>
编写文件上传代码(通过MultipartFile类型的形参来接收文件,该形参名和表单文件名一致)
(3)多文件上传:用多个参数接收或使用MultipartFile数组。
2.5 SpringMVC拦截器
SpringMVC的拦截器(Interceptor)类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。将拦截器按一定的顺序连接成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
拦截器的简单使用
(1)创建拦截器类实现HandlerInterceptor接口,并重写三个方法
(2)配置拦截器(在SpringMVC配置文件中)
<!-- 配置拦截器,可包含多个,按顺序进行拦截 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 对哪些资源执行拦截操作 -->
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="对哪些资源不进行拦截"/>
<bean class="拦截器的全限定包名"/>
</mvc:interceptor>
</mvc:interceptors>
2.6 SpringMVC异常处理
系统的Dao、Service、Controller的异常都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理:
- 简单异常处理器
SpringMVC已经定义好了SimpleMappingExceptionResolver,只需在使用时把异常和视图的映射进行配置即可。<!-- 配置简单异常处理器 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="defaultErrorView" value="默认错误视图页面"/> <property name="exceptionMappings"> <map> <entry key="异常1" value="异常1对应的视图1"/> <entry key="异常2" value="异常2对应的视图2"/> </map> </property> </bean>
- 自定义异常处理器
(1)创建自定义异常处理器类实现HandlerExceptionResolver接口并重写resolveException方法(通过传入的不同异常设置不同的页面信息)
(2)配置自定义异常处理器(由于已经在自定义类中实现了对不同异常的处理对应的视图信息,因此只需要注入即可)<!-- 配置自定义异常处理器 --> <bean class="自定义异常的全限定包名"/>
3. Mybatis
Mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。Mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。最后Mybatis框架执行sql并将结果映射为java对象并返回,采用ORM(对象关系映射:Object Relational Mapping)思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。Mybatis3官网
3.1 Mybatis简单使用
(1)添加mybatis坐标(包含mysql-connector-java坐标)
(2)创建数据库基本表(以用户表user为例)
(3)编写实体类(User实体类为例)
(4)编写映射文件UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
<!-- 1. 查询全部User -->
<select id="selectAll" resultType="com.superm.entity.User">
select * from user
</select>
<!-- 2. 添加User -->
<insert id="insertUser" parameterType="com.superm.entity.User">
insert into user values(null, #{name}, #{age})
</insert>
<!-- 3. 修改User -->
<update id="updateUser" parameterType="com.superm.entity.User">
update user set name=#{name}, age=#{age} where id=#{id}
</update>
<!-- 4. 删除User -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
</mapper>
(5)编写核心文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 数据源环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="com.superm.mapper/UserMapper.xml"/>
</mappers>
</configuration>
(6)编写测试类(用到Mybatis常用的API)
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获得sqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(); //有参数autoCommit设置为true则事务会自动提交
//执行sql语句
//1. 查询全部User对象
List<User> userList = sqlSession.selectList("userMapper.selectAll");
//2. 添加User
int num1 = sqlSession.insert("userMapper.insertUser",new User(3,"李四",23));
//3. 更改User
int num2 = sqlSession.update("userMapper.updateUser", new User(3, "王五", 28));
//4. 删除User
int num3 = sqlSession.delete("userMapper.deleteUser", 3);
sqlSession.commit(); //提交事务,增删改需要,查询不需要
//sqlSession.rollback(); //回滚事务
//释放资源
sqlSession.close();
3.2 Mybatis核心配置文件
- environments标签:数据库环境的配置,支持多环境配置
(1)事务管理器(transactionManager)
JDBC :直接使用JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
MANAGED:容器来管理事务的整个生命周期,默认会关闭连接。
(2)数据源(dataSource)
UNPOOLED:每次请求时打开和关闭连接(没有用到连接池)。
POOLED:利用连接池。
JNDI:为了能在EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文应用。 - mappers标签:加载映射,加载方式如下:
(1)resource:使用相对于类路径的资源引用。
(2)url:使用完全限定资源定位符(URL)。
(3)class:使用映射器接口实现类的完全限定类名。
(4)name:将包内的映射器接口实现全部注册为映射器。(用的package标签) - properties标签:加载外部的properties文件,使用${ }来获取数据
- typeAliases标签:给数据类型起别名,对于一些常用类型,Mybatis已经设置好别名,如string、int、boolean、list、array等。
- typeHandlers标签:类型处理器,将java数据类型和jdbc数据类型进行相互转换。
(1)定义转换类实现TypeHandler接口或继承BaseTypeHandler类(并重写4个方法)。
(2)在Mybatis核心配置文件中进行注册。//自定义类实现在java中是date,在数据库中是bigint类型 public class DateHandler extends BaseTypeHandler<Date> { @Override //将java类型转换为数据库需要的类型 public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { long time = parameter.getTime(); ps.setLong(i,time); } @Override //将数据库中类型转换为java类型 public Date getNullableResult(ResultSet rs, String columnName) throws SQLException { long time = rs.getLong(columnName); Date date = new Date(time); return date; } @Override //将数据库中类型转换为java类型 public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException { long time = rs.getLong(columnIndex); Date date = new Date(time); return date; } @Override //将数据库中类型转换为java类型 public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { long time = cs.getLong(columnIndex); Date date = new Date(time); return date; } }
<!-- 注册类型处理器 --> <typeHandlers> <typeHandler handler="com.superm.handler.DateHandler"/> </typeHandlers>
- plugins标签:插件标签,Mybatis可以使用第三方的插件来对功能进行扩展,如PageHelper分页助手插件。
(1)导入PageHelper坐标(pagehelper,5.3.2版本)。
(2)在Mybatis核心配置文件中配置PageHelper插件。
(3)分页的使用<!-- 配置分页助手插件 --> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
//设置分页相关参数(当前页+显示条数) PageHelper.startPage(1,2); List<User> userList = mapper.getAll(); //获取分页相关参数 PageInfo<User> pageInfo = new PageInfo<>(userList); pageInfo.getPageNum(); //获取当前页 pageInfo.getPages(); //总页数 pageInfo.getNextPage();//下一页 pageInfo.getTotal(); //总条数 pageInfo.isIsFirstPage(); //是否是第一页
3.3 Mybatis的dao层实现
- 传统实现方式:创建dao层接口与实现类,在实现类中用mybatis常用的API来完成对数据库的操作。
- 代理开发方式
Dao接口开发只需编写Dao接口,由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Dao接口开发规范:
(1)Mapper.xml映射文件的namespace与dao接口的全限定名相同。
(2)Dao接口方法名和Mapper.xml映射文件中定义的每个statement的id相同。
(3)Dao接口方法的输入参数类型和Mapper.xml映射文件中定义的每个sql的parameterType的类型相同。
(4)Dao接口方法的输出参数类型和Mapper.xml映射文件中定义的每个sql的resultType的类型相同。UserDao mapper = sqlSession.getMapper(UserDao.class); //根据sqlSession获取Dao接口的实现,再调用接口方法即可
3.4 Mybatis映射文件-动态sql
- 动态sql之if标签
根据实体类的不同取值,使用不同的SQL语句来进行查询,例如:当id不空时根据id进行查询。select * from user <where> <if test="id!=0"> and id=#{id} </if> </where>
- 动态sql之foreach标签
循环执行的sql拼接操作,例如:查询id是否在某一组id中,即类似 where id in(1,2,3)。select * from user <where> <foreach collection="list" open="id in(" close=")" item="id" separator=","> #{id} </foreach> </where>
- 动态sql之sql标签
对重复sql语句的抽取。<!-- 抽取sql --> <sql id="selectSql">select * from user</sql> <!-- 引用sql --> <include refid="selectSql"></include>
3.5 Mybatis多表查询
<resultMap id="id名" type="返回类型">
<!-- column:基本表的字段名称; property:实体的属性名称 -->
<id column="主键字段" property="主键对应的属性名"/>
<result column="字段名" property="字段对应的属性名"/>
<!-- 配置集合信息, property:集合名称; ofType:集合中的数据类型 -->
<collection property="" ofType=""></collection>
</resultMap>
3.6 Mybatis注解开发
- 在Mybatis配置文件中加载映射关系
<!-- 加载映射关系 --> <mappers> <!-- 指定接口所在的包 --> <package name="com.superm.dao"/> </mappers>
- 在Dao的接口中的方法上使用注解,同时将sql语句写入作为参数即可
(1)@Select
:实现查询
(2)@Insert
:实现新增
(3)@Update
:实现更新
(4)@Delete
:实现删除 - Mybatis的注解实现复杂映射开发
对于多表查询:@Result中的属性,property(要封装的属性名称)、column(根据哪个字段去再次查询)、javaType(要封装的实体类型,.class)、one=@One(select="要再次根据column查询的方法全限定方法名")、many=@Many(select="要再次根据column查询的方法全限定方法名")。