spring
概述
Spring是分层的java SE/EE应用full-stack轻量级开源框架,以loC(Inverse Of Control:控制反转) 和 AOP(Aspect Oriented Programming:面向切面编程) 为内核。
提供了展示层SpringMVC和持久层SpringJDBCTemplate以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的javaEE企业应用开源框架
优势
- 1、方便解耦,简化开发
- 2、AOP编程的支持
- 3、声明式事务的支持
- 4、方便程序的测试
- 5、方便继承各种优秀框架
- 6、减低javaEE API的使用难度
- 7、Java源码是经典学习范例
IOC
什么是IOC
控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
2)使用IOC目的:为了耦合度降低
正转
- 由程序员进行对象的创建和依赖注入称为正转,程序员说了算。
Student stu = new Student();
stu.setName("张三");
stu.setAge(22);
反转
- 由Spring容器创建对象和依赖注入称为反转,将控制权从程序员手中夺走,由给Spring容器,称为反转。
/*
容器启动,启动瞬间对象创建
打印====》无参构造方法
*/
<bean id="stu" class="mzj.pojo.Student"/>
2、IOC底层原理
1)xml解析、工厂模式、反射
Ioc(接口)
-
1、思想基于IOC容器完成,IOC容器底层就是对象工厂 -
2、Spring提供IOC容器实现两种方式:(两个接口) -
1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
加载配置文件时候不会创建对象,在获取对象(使用)才会创建对象
-
2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
加载配置文件时候就会把再配置文件对象进行创建
Bean管理
1、基于xml配置文件方式实现
2、基于注解方式
IOC操作Bean管理(FactoryBean)
- 1、Spring有两种类型bean,一种普通bean,另外一种工厂bean(factoryBean)
- 2、普通bean:配置文件中定义bean类型就是返回类型
- 3、工厂bean:在配置文件定义bean类型可以和返回类型不一样
配置文件
App.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.impl.UserDaoImpl"/>
</beans>
main方法
package Mzj.Demo;
import Mzj.dao.UserDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserDaoDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("App.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
}
UserDao
package Mzj.dao;
public interface UserDao {
public void save();
}
UserDaoImpl
package Mzj.impl;
import Mzj.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("saving…………");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eq3TXbF1-1653223158134)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220410154414204.png)]
对象的实例
单个——加载时创建
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.impl.UserDaoImpl" scope="singleton"/>
</beans>
多个——获取bean时创建
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.impl.UserDaoImpl" scope="prototype"/>
</beans>
Bean生命周期
- 1、通过构造器创建bean实例(无参数构造)
- 2、为bean的属性设置值和对其他bean引用(调用set方法)
- 3、调用bean的初始化方法(需要进行配置初始化方法
- 4、bean可以使用了(对象获取到了)
- 5、当容器关闭时候,调用bean的销毁方法(需要进行配置销毁的方法)
init-method:指定类中的初始化方法名称
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.impl.UserDaoImpl" init-method="init"/>
</beans>
destroy-method:指定类中销毁方法名称
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.impl.UserDaoImpl" destroy-method="destroy"/>
</beans>
Bean实例化三种方式
- 无参构造方法实例化
- 工厂静态方法实例化
- 工厂实例方法实例化
工厂静态方法实例化
App.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.factory.StaticFactory" factory-method="getUserDao"/>
</beans>
StaticFactory
package Mzj.factory;
import Mzj.dao.UserDao;
import Mzj.impl.UserDaoImpl;
public class StaticFactory {
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
main
import Mzj.dao.UserDao;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
@Test
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("App.xml");
UserDao userDao1 = (UserDao) app.getBean("userDao");
System.out.println(userDao1);
app.close();
}
}
工厂实例方法实例化
App.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="factory" class="Mzj.factory.DynamicFactory"/>
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"/>
</beans>
Bean的依赖注入方式
Bean的依赖注入概念
依赖注入(DependencyInjection):它是Spring框架核心IOC的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。
IOC解耦只是降低他们的依赖关系,但是不会消除。例如:业务层仍会调用持久层的方法。
那这种业务蹭喝持久层的依赖关系,在使用Spring之后,就让Spring来维护了。
set方法
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="impl.UserDaoImpl"></bean>
<bean id="user" class="bean.User">
<property name="username" value="绍利临"/>
<property name="password" value="12312312"/>
</bean>
</beans>
User
package bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
private String username;
private String password;
public void test1(){
System.out.println(username+"======="+password);
}
}
main
package controller;
import bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
public class TestController {
@Test
public void testadd(){
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) app.getBean("user");
user.test1();
}
}
构造方法
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="impl.UserDaoImpl"></bean>
<bean id="user" class="bean.User">
<constructor-arg name="username" value="绍利临"></constructor-arg>
<constructor-arg name="password" value="12312312"></constructor-arg>
</bean>
</beans>
User
package bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
private String username;
private String password;
public void test1(){
System.out.println(username+"======="+password);
}
}
main
package controller;
import bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
public class TestController {
@Test
public void testadd(){
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) app.getBean("user");
user.test1();
}
}
p命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="user" class="bean.User" p:password="123123" p:username="绍利临">
</bean>
</beans>
注入空值或特殊符号
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="user" class="bean.User">
<!--set方法-->
<property name="username" value="绍利临"/>
<property name="password" value="12312312"/>
<!--空值-->
<property name="test">
<null></null>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="user" class="bean.User">
<property name="username" value="绍利临"/>
<property name="password" value="12312312"/>
<property name="test">
<value><![CDATA[<<南京>>]]></value>
</property>
</bean>
</beans>
注入外部bean
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="userDao" class="impl.UserDaoImpl"></bean>
<bean id="userService" class="impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
package impl;
import dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("userDao…………");
}
}
package impl;
import dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import service.UserService;
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void add() {
userDao.add();
}
}
提取list集合类型属性注入
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<util:list id="bookList">
<value>绍利临</value>
<value>李德新</value>
<value>增配设</value>
</util:list>
<bean id="book" class="">
<property name="" ref="bookList"></property>
</bean>
</beans>
Bean的依赖注入的数据类型
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="Mzj.impl.UserDaoImpl">
<property name="username" value="zhangsan"/>
<property name="age" value="18"/>
<property name="strList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<property name="userMap">
<map>
<entry key="user1" value-ref="user1"/>
<entry key="user2" value-ref="user2"/>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">p1</prop>
<prop key="p2">p2</prop>
<prop key="p3">p3</prop>
</props>
</property>
</bean>
<bean id="user1" class="Mzj.domain.User">
<property name="name" value="tom"/>
<property name="addr" value="beijing"/>
</bean>
<bean id="user2" class="Mzj.domain.User">
<property name="name" value="Mzj"/>
<property name="addr" value="guangzhou"/>
</bean>
</beans>
UserDaoImpl
package Mzj.impl;
import Mzj.dao.UserDao;
import Mzj.domain.User;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@Data
public class UserDaoImpl implements UserDao {
private List<String> strList;
private Map<String, User> userMap;
private Properties properties;
private String username;
private int age;
@Override
public void save() {
System.out.println(username + "=======" + age);
System.out.println(strList);
System.out.println(userMap);
System.out.println(properties);
}
}
map的User对象
package Mzj.domain;
import lombok.Data;
@Data
public class User {
private String name;
private String addr;
}
引入其他文件设置
<import resource="文件名字"/>
Spring相关API
ApplicationContext的实现类
-
1、ClassPathXmlApplicationContext 它是从类的根路径下加载配置文件推荐使用这种 -
2、FileSystemXmlApplicationContext 文件绝对路径导入 -
AnnotationConfigApplicationContext 当使用注解配置容器对象时,需要使用此类来创建spring容器。他用来读取注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7gQIPCg-1653223158135)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220412205440488.png)]
<context:component-scan base-package="Mzj.dao"/>
加载properties文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<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>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
新注解自动配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-llQM11XY-1653223158135)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220412214740017.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bELACu1-1653223158136)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504183118476.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOi5fzDl-1653223158136)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504183316476.png)]
完全注解开发
main
package Mzj.controller;
import Mzj.config.SpringConfig;
import Mzj.impl.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.testng.annotations.Test;
public class TestController {
@Test
public void testadd(){
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
UserServiceImpl userService = (UserServiceImpl) app.getBean("userService");
userService.add();
}
}
UserDaoImpl
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EpeJ9kF7-1653223158136)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504185657272.png)]
UserServiceImpl
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dY3gz5P7-1653223158137)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504185732643.png)]
监听器
- 应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件)方式获取的,但是每次从容器中获得Bean时都要编写 new ClasspathXmlApplicationContext(spring配置文件),这样的弊端是配置文件加载多次,应用上下文对象创建多次。
- 在web项目于中,可以使用ServletContextListener监听web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。
以类来开发注解
SpringConfiguration类
package Mzj.config;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan("Mzj.impl")
@Import(sqlconfig.class)
public class SpringConfiguration {
}
sqlconfig类
package Mzj.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@PropertySource("classpath:jdbc.properties")
public class sqlconfig {
@Bean("dataSource")
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///day17");
dataSource.setUser("root");
dataSource.setPassword("936541");
return dataSource;
}
}
配置监听器
web.xml
<listener>
<listener-class>Mzj.listener.ContextLoaderListener</listener-class>
</listener>
package Mzj.listener;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("App.xml");
ServletContext servletContext = sce.getServletContext();
servletContext.setAttribute("app",app);
System.out.println("调用了监听器");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
ServletContextListener.super.contextDestroyed(sce);
}
}
package Mzj.web;
import Mzj.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(value = "/UserServiceServlet")
public class UserServiceServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ClassPathXmlApplicationContext app = (ClassPathXmlApplicationContext) servletContext.getAttribute("app");
UserService bean = app.getBean(UserService.class);
System.out.println(bean);
}
}
spring5新功能
- 1、整个Spirng5框架的代码基于java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除了
- 2、Spring5框架自带了通用的日志封装
- 1)Spring5已经移除了Log4jConfigListener,官方建议使用Log4j2
整合日志框架
log4j2
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="INFO">
<appenders >
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} -msg%n"/>
</console>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
Spring5框架核心容器支持@Nullable注解
1)@Nullable注解可以使用在方法上面,属性上面,参数上面,标识方法返回可以为空,属性值可以为空,参数值可以为空
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KA87FzuF-1653223158137)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504200827340.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2AO34zU-1653223158137)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504200839697.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LXe4kvbb-1653223158137)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504200858825.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zqQHtDvw-1653223158137)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504201438359.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RG5VKq7d-1653223158138)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220504200352774.png)]
整合Junit4
package Ts;
import Mzj.config.SpringConfig;
import Mzj.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class Jtest4 {
@Autowired
UserService userService;
@Test
public void test1(){
userService.add();
}
}
整合Junit5
package Ts;
import Mzj.config.SpringConfig;
import Mzj.service.UserService;
import org.junit.Test;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import javax.annotation.Resource;
@SpringJUnitConfig(classes = SpringConfig.class)
public class Jtest5 {
@Resource
UserService userService;
@Test
public void test1(){
userService.add();
}
}
Webflux
Webflux使用当前比较流程响应式编程出现的框架,是一种异步非阻塞的框架,异步非阻塞的框架,异步非阻塞的框架在Servlet3.1以后才支持,核心是基于Reactor的相关API实现的。
java8以及之前版本
- 提供的观察者模式俩个乐力Observer和Observable
响应式编程(Reactor)
- 1)响应式编程操作中,Reactor是满足Reactive规范框架
- 2)Reactor有俩个核心类,Mono 和Flux,这两个类实现接口Publisher,提供丰富操作符。Flux对象实现发布者,返回N个元素;Mono实现翻发布者,返回0或者1个元素
- 3)Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号:
元素值,错误信息,完成信号,错误信号和完成信号都代表种植信号,终止信号用于告诉订阅者数据流结束了
4)
package mzj.webflux_01.reactor8;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class TestReactor {
public static void main(String[] args) {
Flux.just(1,2,3,4);
Mono.just(1);
Integer[] array = {1,2,3,4};
Flux.fromArray(array);
List<Integer> list = Arrays.asList(array);
Flux.fromIterable(list);
Stream<Integer> stream = list.stream();
Flux.fromStream(stream);
}
}
5)三种信号特点
- 错误信号和完成信号都是终止信号,不能共存的
- 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示空数据流
- 如果没有错误信号,没有完成信号,表示无限数据流
6)调用just或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vcTL6I8o-1653223158138)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220506203758197.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9pRA94aZ-1653223158138)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220506205815089.png)]
SpringMVC
什么是MVC
MVC是一种软件架构的思想
M:Model,模型层,之工程中的JavaBean,作用是处理数据
JavaBean分为两类:
- 一类称为实体类Bean:专门存储业务数据的
- 一类称为业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
V:View视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是用来接收请求和响应浏览器
MVC的工作流程:
用户通过视图层发送请求到服务器,在服务器中请求被Controller调用相应的Model层处理请求,处理完毕将结果返回到Controoler,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
web开发底层是servlet,框架是在servlet基础上面加入一些功能,让你做web开发方便。
SpringMVC就是一个Spring。Spring是容器,ioc能够管理对象,@Controller SpringMVC能够创建对象,放入到容器中(SpringMVC容器),springMVC容器中放的是控制器对象,
我们要做的是使用@Controller 创建对象,把对象放入到springMVC容器中,把创建的对象作为控制器使用,这个控制器对象能接收用户的请求,显示处理结果,就当作是一个servlet使用。
框架的核心对象
- 1)DispatcherServlet叫做中央调度器,是一个servlet,它的父类是继承HttpServlet
- 2)DispatcherServlet也叫做前端控制器(front controller)
- 3)DispatcherServlet负责接收用户提交的请求,调用其他的控制器对象,并把请求的处理结果显示给用户
快速代码实现
默认配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-appxmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:MVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
创建请求控制器
由于前端控制器对浏览器发送的请求进行了统一的处理,到那时具体的请求有不同的处理过程,因此需要创建具体请求的类,即请求控制器
请求控制器中每一个处理请求的方法成为控制器方法
因为SpringMVC的控制器由一个POJO(普通的java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MyController {
@RequestMapping("/some")
public ModelAndView dosome(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","欢迎使用mvc");
mv.addObject("fun","执行的是some方法");
mv.setViewName("show");
return mv;
}
}
mvc.xml—jsp
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/subview/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
mvc.xml—themleaf
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="Mzj.controller"/>
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/tm/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
@RequestMapping详解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
value
@RequestMapping(value = {"/success1","success2"})
public String success(){
return "success";
}
method
@RequestMapping(value = {"/success1","success2"},
method = {RequestMethod.GET,RequestMethod.POST})
public String success(){
return "success";
}
params属性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mOdbekl3-1653223158138)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505152142299.png)]
@RequestMapping(value = {"/success1","success2"},
method = {RequestMethod.GET,RequestMethod.POST},
params = {"username != admin"}
)
public String success(){
return "success";
}
SpringMVC支持ant风格的路径
-
1、?:表示任意的单个字符 @GetMapping(value = {"/a?a/testAnt1"})
public String testAnt1(){
return "success";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uuyMVb2o-1653223158139)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505153932670.png)] -
2、*:表示任意的0个或多个字符 @GetMapping(value = {"/a*a/testAnt1"})
public String testAnt1(){
return "success";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uv4aVTCJ-1653223158139)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505154049924.png)] -
3、**:表示任意的一层或多层目录 @GetMapping(value = {"/**/testAnt1"})
public String testAnt3(){
return "success";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V0Ovh7Dp-1653223158139)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505154510938.png)]
注意:在使用** 时,只能使用/**/xxx 的方式
RESTFul风格
- 表现层资源状态转移
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mi11654O-1653223158139)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220510093919595.png)]
@GetMapping(value = {"/testRest1/{id}/{username}"})
public String testRest1(@PathVariable("id") String id,@PathVariable("username") String username){
System.out.println("id:"+id+",username:"+username);
return "success";
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jtLNotyO-1653223158140)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505160917117.png)]
RESTFul的实现
web.xml
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fMfJ1goL-1653223158140)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220510103156534.png)]
域对象共享数据
-
1、servletAPI向request域对象共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8SJHjszZ-1653223158140)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505164517660.png)] -
2、使用ModeAndView向request域对象共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JK8LCI6h-1653223158140)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505164532555.png)] -
3、使用Model向request域对象共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GrzaRnZ6-1653223158140)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505164546410.png)] -
4、使用Map向request域对象共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pwuwU2rU-1653223158140)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505164555061.png)] -
5、使用ModelMap向request域对象共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kAOoxk7e-1653223158141)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505164616643.png)] -
这些实质上就是BuindingAwareModelMap -
6、使用session域共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tw1cUvZ1-1653223158141)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505165936768.png)] -
7、向application域共享数据 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXqm5AuC-1653223158141)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505170036551.png)]
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进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。
SpringMVC的执行流程(大概流程)
浏览器
——>请求网页——>
前端控制器DispathcerServlet
——>请求查询Handler ——>
处理器映射器HandlerMapping
——>返回处理器执行链HandlerExecutionChain——>
前端控制器DIspathcherServlet
——>请求Handler——>
处理器适配器HandlerAdaptor
——>请求 ——>
处理器Handler
——>响应——>
处理适配器HandlerAdaptor
——>返回ModelAndView
前端控制器DispatcherServlet
——>请求视图解析器——>
视图解析器ViewResolver
——>返回视图View对象——>
前端控制器DispatcherServlet
——>渲染视图——>
视图页面jsp
SpringMVC组件解析
作用:用于建立请求URL和处理请求方法之间的对应关系
位置:
- 类上,请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录
- 方法上,请求URL的第二级访问目录,与类上的使用@RequestMapping标注的一级目录一起组成访问虚拟路径
属性:
- value:用于指定请求的URL。它和path属性的作用是一样的
- method:用于指定请求的方式
- params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
例如:
- params={“accountName”},表示请求参数必须有accountName
- params={“moneny!100”},表示请求参数中money不能是100
SpringMVC注解解析
1、mvc命名空间引入
命名空间
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
约束地址
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
2、组件扫描
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用
<context:compent-scan base-pachage="controller文件"/>
进行组件扫描
知识要点
SpringMVC的相关组件
- 前端控制器:
- 处理器映射器:
- 处理器适配器:
- 处理器:
- 视图解析器:
- 视图:
SpringMVC的注解和配置
回写数据
2、返回对象或集合
在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样配置可以比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置。
<mvc:annotation-driven/>
在SpringMVC的各个组件中,处理映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
在使用mvc:annotation-driven自动加载 (处理映射器)和(处理适配器),可用在Springj-xml.xml配置文件中使用mvc:annotation-driven替代注解处理器和适配器的配置。
同时使用mvc:annotation-driven默认底层就会继承jackson进行对象或集合的json格式字符串的转换。
数据响应
SpringMVC的数据响应方式
- 1、页面跳转
- 直接返回字符串
- 通过ModelAndView对象返回
- 2、回写数据
获得集合参数
静态资源放行
<mvc:default-servlet-handler></mvc:default-servlet-handler>
乱码问题
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
- value:与请求参数名称
- required:此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
- defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
@RequestMapping(value = "/quick16")
@ResponseBody
public void save16(@RequestParam(value = "name",required = false,defaultValue = "Mzj") String username) {
System.out.println(username);
}
Restful风格的参数
概述
Restful 是一种软件风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的如那件,基于这个风格设计的软件可以更简洁,更有层次,更容易实现缓存机制等。
Restful风格的请求时使用"url+请求方式"表示一次请求目的,HTTP协议里面四个表示操作方式的动词如下:
- GET:用于获取资源
- POST:用于新建资源
- PUT:用于更新资源
- DELETE:用于删除资源
Restful参数获取
@RequestMapping(value = "/quick17/{username}")
@ResponseBody
public void save17(@PathVariable(value = "username") String username) {
System.out.println(username);
}
转换器
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="converter.DateConverter"/>
</list>
</property>
</bean>
package converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String daeStr) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(daeStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
文件上传解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSizePerFile" value="5242800"/>
<property name="maxUploadSize" value="5242800"/>
</bean>
JdbcTemplate
package test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import java.beans.PropertyVetoException;
public class JdbcTemplateTest {
@Test
public void test1() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///day17");a
dataSource.setUser("root");
dataSource.setPassword("936541");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
int row = jdbcTemplate.update("insert into account values(?,?)", "tom", 5000);
System.out.println(row);
}
}
Spring产生JdbcTemplate对象
SpringMVC拦截器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzjvFSsh-1653223158141)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507203410483.png)]
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
package interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.handler.Handler;
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
结果:
preHandle
目标资源执行
postHandle
afterCompletion
SpringMVC异常处理
简单异常处理器SimpleMappingExceptionResolver
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<map>
<entry key="java.lang.ClassCastException" value="error1"/>
<entry key="java.lang.ClassCastException" value="error2"/>
</map>
</property>
</bean>
注解
package mzj.spring_boot_web.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{myConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQ0OsYD6-1653223158142)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507204541501.png)]
HttpMessageConverter
- 报文信息转换器,将请求报文转换为java对象,获将java对象转换为响应报文HttpMessageConverter提供了两个注解和两个类型:
@RequestBody
@ResponseBody
@RequestEntity
@ResponseEntity
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WIpdkhpj-1653223158142)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507194204973.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RN3z3sOy-1653223158142)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507194242329.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eXDEIsiZ-1653223158142)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507194348533.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dgdf1gwe-1653223158142)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507195221637.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ZG5eCdh-1653223158143)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220507195246250.png)]
Spring 的AOP简介
概述
AOP为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,l利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的课重用性,同时提高了开发的效率。
- Target(目标对象):代理的目标对象
- Proxy(代理):一个类被AOP织入增强后,就产生一个代理类
- Joinpoint(连接点):所以连接点点是指那些被拦截的点。在这些点指的是方法,因为spring只支持方法类型的连接点。
- Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
- Advice(通知/增强):所谓通知时至拦截到Joinpoint之后所要做的事情就是通知
- Aspect(切面):是切入点和通知(引介)的结合
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态dialing织入,而Aspectj采用编译器织入和类装载期织入
AOP底层使用哪种代理方式
AOP底层使用动态代理
有两种情况动态代理
- 1、有接口情况,使用JDK动态代理
- 2、没有接口情况,使用CGLIB动态代理
在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
实现JDK方式
方法有三个参数:
第一参数:类加载器
第二参数:增强方法所在的类,这个类实现的接口,支持多个接口
第三参数:实现这个接口InvocationHandler,创建代理对象,写增强方法
package mzj.proxy5;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
public static Object getAgent(Service service, AOP aop) {
return Proxy.newProxyInstance(
service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(
Object proxy,
Method method,
Object[] args) throws Throwable {
Object obj = null;
try {
aop.before();
obj = method.invoke(service, args);
aop.after();
} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
aop.exception();
}
return obj;
}
}
);
}
}
创建接口,实现方法
package Mzj;
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
package Mzj;
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public String update(String id) {
return id;
}
}
使用JDKProxy
package Mzj;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int add = dao.add(1, 2);
System.out.println("re:" + add);
}
}
class UserDaoProxy implements InvocationHandler {
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行…………" + method.getName() + ":传递的参数……" + Arrays.toString(args));
Object res = method.invoke(obj, args);
System.out.println("方法之后执行…………" + obj);
return res;
}
}
AOP术语
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w8lFsWYY-1653223158143)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505203617266.png)]
切面:就是哪些重复的,公共的,通用的功能称为切脉你,例如:日志,事务,权限
连接点:就是目标方法。因为在目标方法中要实现目标方法的功能和切面功能。
切入点:多个连接点构成切入点。切入点可以是一个没有标反复噶,可以是一个类中的所有方法,可以是某个包下的所有类中的方法。
AOP准备工作
- 1、Spring框架一般都是基础与AspectJ实现AOP操作
- 1)什么是AspectJ
- AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
- 2、基于AspectJ实现AOP操作
- 1)基于xml配置配置文件实现
- 2)基于注解方式实现(使用)
原生
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cA5fGEpC-1653223158143)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220511215612010.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9YHXm7mN-1653223158143)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220511220052086.png)]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
">
<bean id="target" class="aop.TargetTest"/>
<bean id="myAspect" class="aop.MyAspect"/>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* aop.*.*(..))"/>
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
</beans>
例图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqeRlIsB-1653223158144)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220511215301758.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mVTi94ME-1653223158144)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220511215341275.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x9PXLWjo-1653223158144)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220511215219988.png)]
切点表达式语法
execution([修饰符]返回值/类型 包名.类名.方法名)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-neIDuQRP-1653223158144)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505204453427.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ueuQdI4f-1653223158144)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505204503985.png)]
- 访问修饰符可以省略
- 返回值类型、包名、类名、方法名可以使用星号
* 代表任意 - 包名与类名之间一个点
. 代表当前包下的类,俩个点.. 表示当前包及子包下的类 - 参数列表可以使用两个点
.. 表示任意个数,任意类型的参数列表
<aop:通知类型 method="切面类中方法名" pointcut="切点表达式"/>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Djy7s5v-1653223158145)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220511221133509.png)]
名称 | 标签 | 说明 |
---|
前置通知 | aop:before | 用于配置前置通知。指定增强的方法在切入点方法之前执行 | 后置通知 | aop:after-returning | 用于配置后置通知。指定增强的方法在切入点方法之后执行 | 环绕通知 | aop:around | 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 | 异常抛出通知 | aop:throwing | 用于配置异常抛出通知。指定增强的方法在出现异常时执行 | 最终通知 | aop:after | 用于配置最终通知。无论增强方式是否有异常都会执行 |
切点表达式抽取
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
">
<bean id="target" class="aop.TargetTest"/>
<bean id="myAspect" class="aop.MyAspect"/>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* aop.*.*(..))"/>
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
</beans>
基于注解的AOP开发
1、创建目标接口和目标类(内部有切点)
2、创建切面类(内部有增强方法)
3、将目标类和切面类的对象创建权交给spring
4、在切面类中使用注解配置织入关系
5、在配置文件中开启组件扫描和AOP的自动代理
6、测试
1、创建类,在类中定义方法
package aopanno;
public class UserDaoImpl {
public void add() {
System.out.println("add…………");
}
}
2、创基增强类(编写增强逻辑)
1)在增强类里面,创建放啊,让不同方法代表不同通知类型
package aopanno;
public class UserProxy {
public void before(){
System.out.println("beforea……");
}
}
3、进行通知的配置
1)spring配置文件,开启注解扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="aopanno"/>
</beans>
2)使用注解创建User和UserProxy对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zy7rAaVQ-1653223158145)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505205736571.png)]
3)在增强类上面添加注解@aspect
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BjK3jOUM-1653223158145)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505210913497.png)]
4)在spring配置文件中开启生成代理对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<context:component-scan base-package="aopanno"/>
<aop:aspectj-autoproxy/>
</beans>
4、配置不同类型的通知
1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点
package mzj.s01;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Locale;
@Component
@Aspect
public class MyAspect {
@Before(value = "execution(public String mzj.s01.SomeServiceImpl.dosome(String,int))")
public void myBefore(JoinPoint joinPoint) {
System.out.println("切面方法中的前置通知功能实现");
System.out.println(joinPoint.getSignature());
System.out.println(Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(value = "execution(* *.*(..))", returning = "obj")
public void myAfterReturning(Object obj) {
System.out.println("后置通知功能实现");
if (obj != null) {
if (obj instanceof String) {
obj = obj.toString().toUpperCase();
System.out.println("在切面方法中目标方法的返回值" + obj);
}
}
}
@Around("execution(* *.*(..))")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知的前置功能");
Object obj = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
System.out.println("环绕通知的后置功能");
return obj.toString().toUpperCase();
}
@After(value = "execution(* *.*(..))")
public void myAfter() {
System.out.println("最终通知的功能");
}
}
使用方法进行抽取
package aopanno;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class UserProxy {
@Pointcut(value = "execution(* aopanno.UserDaoImpl.add(..))")
public void pointDemo(){
}
@Before(value = "pointDemo()")
public void before(){
System.out.println("beforea1……");
}
}
增强优先级
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TeUhvKnn-1653223158145)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220505211536697.png)]
编程式事务控制相关对象
PlatformaTransactionManager
PlatformTranscactionManager接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法。
方法 | 说明 |
---|
TransactionStatus getTransaction(TransactionDefination defination) | 获取事务的状态信息 | void commit(TransactionStatus status) | 提交事务 | void rollbakc(TransactionStatus status) | 回滚事务 |
TransactionDefinition
方法 | 说明 |
---|
int getisolationLevel() | 获得事务的隔离级别 | int getPropogationBehavior() | 获得事务的传播行为 | int getTimeout() | 获得超时时间 | boolean isreadOnly() | 是否只读 |
-
1、事务隔离级别 -
mysql:默认的隔离级别是REPEATABLE_READ ,也就是可重复读 -
Oraclr:支持READ_COMMITTED 和SERIALIZABLE 这两种事务隔离级别。默认系统事务隔离级别READ_COMMITTED 设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。 -
ISOLATION_DEFAULT:默认隔离级别 -
ISOLATION_READ_UNCOMMITTED:允许脏读,也就是可能读取到其他会话中未提交事务修改的数据 -
ISOLATTION_READ_COMMITTED:只能读取到已经提交的数据。Oracle等多数数据库默认改级别(不可重复读) -
ISOLATION_REPEATABLE_READ:可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还是存在幻像读,到那时innoDB解决了幻读 -
ISOLATION_SERIALIZABLE:完全串行化的读,每次读都选哟获得表级共享锁,读写相互都会阻塞 -
2、事务传播行为 -
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值) -
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务) -
MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常 -
REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起 -
NOT_SUPPORTED:以非事务方式执行操作,如果当前在事务中,把当前事务挂起 -
NEVER:以非事务方式运行,如果当前存在事务,抛出异常 -
NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似操作 -
超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置 -
是否只读:建议查询时设置为只读
TransactionStatus
TransactionStatus接口提供的是事务具体的运行状态
方法 | 说明 |
---|
boolean hasSavepoint() | 是否存储回滚点 | boolean isCompleted() | 事务是否完成 | boolean isNewTransaction() | 是否是新事务 | boolean isRollbackOnly() | 事务是否回滚 |
三大对象
- PlatformTransactionmanager
- TransactionDefinition
- TransactionStatus
基于XML的声明式事务控制
什么是声明式事务控制
Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来替代代码式的处理事务。
声明式事务处理的作用
- 事务管理不侵入开发的组件。具体俩说业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可。
注意:Spring声明式事务控制底层就是AOP
声明式事务控制的实现
声明式事务控制明确事项:
<bean id="accountService" class="Mzj.Impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<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="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcit" expression="execution(* Mzj.Impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcit"/>
<aop:advisor order="1" advice-ref="txAdvice" pointcut="execution(* Mzj.impl.*.*())"/>
</aop:config>
注解配置声明式事务控制解析
<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>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(propagation = Propagation.REQUIRED,
noRollbackForClassName = "ArithmeticException",
noRollbackFor = ArithmeticException.class,
rollbackForClassName = "",
rollbackFor = ArithmeticException.class,
timeout = -1,
readOnly = false,
isolation = Isolation.DEFAULT)
Mybatis
入门
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="Studentmapper.xml"></mapper>
</mappers>
</configuration>
其中,事务管理器(TransacctionManager)类型有两种:
- JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
- MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE应用服务器的上下文)。默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置为false来阻止它默认的关闭行为。
其中,数据源(dataSource)类型有三种:
- UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
- POOLED:这种数据源的实现利用"池"的概念和JDBC连接对象组织起来。
- JNDI:这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。
create database ssm default charset utf8;
use ssm;
create table `student`(
`id` int(11) auto_increment primary key,
`name` varchar(255) default null,
`email` varchar(255) default null,
`age` int(11) default null
)engine=InnoDB default charset=utf8;
create table `users`(
`id` int(11) auto_increment primary key,
`username` varchar(32) comment '用户名称',
`birthday` date default null comment '生日',
`sex` char(2) default null comment '性别',
`address` varchar(256) default null comment '地址'
)engine=InnoDB AUTO_INCREMENT=27 default charset=utf8;
insert into student(name,email,age) values("张三","zhangsan@126.com",11);
insert into student(name,email,age) values("李四","lisi@126.com",22);
insert into student(name,email,age) values("王五","wangwu@qq.com",33);
insert into student(name,email,age) values("赵六","zhaoliu@qq.com",44);
insert into users values(1,"赵六","2001-02-01","2","安徽");
insert into users values(2,"赵七","2001-02-02","1","高州");
insert into users values(3,"赵八","2001-02-03","2","广州");
insert into users values(4,"赵九","2001-02-04","1","高明");
insert into users values(5,"赵十","2001-02-05","1","日本");
mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.UsersMapper">
<delete id="deleter" parameterType="int">
delete
from users
where id = #{id}
</delete>
<select id="getAll" resultType="users">
select id, username, birthday, sex, address
from users
</select>
<select id="getById" resultType="users" parameterType="int">
select id, username, birthday, sex, address
from users
where id = #{id}
</select>
<select id="getByName" resultType="users" parameterType="String">
select id, username, birthday, sex, address
from users
where username like '%${username}%'
</select>
<select id="getByNameGood" resultType="users">
select id, username, birthday, sex, address
from users
where username like concat('%',#{username},'%')
</select>
<update id="update" parameterType="users">
update users
set username=#{username},
birthday=#{birthday},
sex=#{sex},
address=#{address}
where id = #{id}
</update>
</mapper>
userTest
package com;
import mapper.UsersMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import pojo.Users;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class UseTest {
SqlSession sqlSession;
UsersMapper usersMapper;
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
@Before
public void testBefore() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapCon.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
sqlSession = sessionFactory.openSession();
usersMapper = sqlSession.getMapper(UsersMapper.class);
}
@Test
public void test01() {
List<Users> all = usersMapper.getAll();
all.forEach(System.out::println);
}
@Test
public void test02() throws ParseException {
Users u = new Users(5, "haha", sf.parse("2000-10-20"), "2", "北京");
int update = usersMapper.update(u);
sqlSession.commit();
System.out.println(update);
}
@Test
public void test03() throws ParseException {
Users id = usersMapper.getById(1);
System.out.println(id);
}
@Test
public void test04() throws ParseException {
List<Users> byName = usersMapper.getByName("赵");
System.out.println(byName);
}
@Test
public void test05() throws ParseException {
int deleter = usersMapper.deleter(1);
sqlSession.commit();
System.out.println(deleter);
}
@After
public void testafter() {
sqlSession.close();
}
}
MyBatis对象分析
1)Resources类
就是解析SqlMapConfig.xml文件,创建出相应的对象
InputStream in = Resources.getResourceAsStream("Sqlmapper.xml");
2)SqlSessionFactoryBuilder类
使用ctrl+h快捷键查看本接口的子接口及实现类
DefaultSqlSessionFactory是实现类
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
3)SqlSessionFactory接口
DefaultSqlSession实现类
没有放在resources目录下的xml文件
为实体类注册别名
设置日志输出底层执行的代码
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
MyBatis的动态代理的7个规范
- 1)UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下。
- 2)UsersMapper.xml文件与UserMapper.java的接口的文件名必须一致,后缀不管。
- 3)UsersMapper.xml文件中标签的id值与UserMapper.java的接口中方法的名称完全一致。
- 4)UsersMapper.xml文件中标签的parameterType属性值与UserMapper.java的接口中方法的参数类型完全一致。
- 5)UsersMapper.xml文件中标签的resultType值与UserMapper.java的接口中方法的返回值类型完全一致。
- 6)UsersMapper.xml文件中namespace属性必须是接口的完全限定名称mapper.UsersMapper
- 7)在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称mapper.UsersMapper
#{}占位符
-
传参大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问,防止sql注入。 如何写 -
1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写。 -
2)parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写。 -
3)字符串凭借,一般用于模糊查询中。建议少用,因为有sql注入的风险。 也分两种情况,同样的看parameterType的类型 A、如果parameterType的类型是简单类型,则#{}里随便写,但是分版本,如果是3.5.1及以下的,只写value B、如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称
返回主键id
<insert id="create" parameterType="com.sxgn.springcloud.entity.Payment" useGeneratedKeys="true" keyProperty="id">
INSERT INTO payment(serial) VALUES (#{serial})
</insert>
useGeneratedKeys=“true” 表示给主键设置自增长 keyProperty=“userId” 表示将自增长后的Id赋值给实体类中的userId字段。 parameterType=“com.chenzhou.mybatis.User” 这个属性指向传递的参数实体类
这里提醒下, 中没有resultType属性,不要乱加
<insert id="create">
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO payment(serial) VALUES (#{serial})
</insert>
selectKey 中没有resultType属性,但是 标签是有的。
order=“AFTER” 表示先执行插入语句,之后再执行查询语句。
可被设置为 BEFORE 或 AFTER。
如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。
如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用 keyProperty=“userId” 表示将自增长后的Id赋值给实体类中的userId字段。
SELECT LAST_INSERT_ID() 表示MySQL语法中查询出刚刚插入的记录自增长Id
foreach
<select id="getByIds" resultType="users">
select
<include refid="U"/>
from users
where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
SqlSession工厂对象SqlSessionFactory
方法 | 解释 |
---|
openSession | 会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提交该事务,更新操作数据才会持久化到数据库中 | openSession(booleanautoCommit) | 参数为是否自动提交,如果设置为true,那么不需要手动提交事务 |
Dao层实现
代理开发方式
采用Mybatis的代理开发方式实现DAO层的开发,这种方式是我们后面进入企业的主流。
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),有mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循一下规范:
1、Mapper.xml文件中的namespace于mapper接口的全限定名相同
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
测试代理方式
package mzj.service;
import mzj.Impl.UserMapperImpl;
import mzj.dao.UserMapper;
import mzj.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class ServiceDemo {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("mapper/sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAll();
List<User> byId = mapper.findById(2);
System.out.println(byId);
}
}
MyBatis映射文件深入
动态sql语句
<select id="findByC" resultType="user" parameterType="user">
select *
from user
<where>
<if test="id!=0 and id !=''">
and id=#{id}
</if>
<if test="age!=0">
and age=#{age}
</if>
</where>
</select>
<select id="findByD" resultType="user" parameterType="user">
select *
from user
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
sql抽取
<sql id="selectUser">select *
from user</sql>
<select id="findAll" resultType="user">
<include refid="selectUser"/>
</select>
typeHandlers标签
<typeHandlers>
<typeHandler handler="mzj.handler.DateTypeHandler"/>
</typeHandlers>
package mzj.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class DateTypeHandler extends BaseTypeHandler<Date> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
long time = parameter.getTime();
ps.setLong(i,time);
}
@Override
public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
long aLong = rs.getLong(columnName);
Date date = new Date(aLong);
return date;
}
@Override
public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
long aLong = rs.getLong(columnIndex);
Date date = new Date(aLong);
return date;
}
@Override
public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
long aLong = cs.getLong(columnIndex);
Date date = new Date(aLong);
return date;
}
}
分页助手
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>
PageHelper.startPage(1,3);
PageInfo<User> userPageInfo = new PageInfo<>(all);
System.out.println("当前页:"+userPageInfo.getPageNum());
System.out.println("每页显示条数:"+ userPageInfo.getPageSize());
System.out.println("总条数:"+ userPageInfo.getTotal());
System.out.println("总页数:"+userPageInfo.getPages());
System.out.println("上一页:"+ userPageInfo.getPrePage());
System.out.println("下一页:"+userPageInfo.getNextPage());
System.out.println("是否是第一个:"+userPageInfo.isIsFirstPage());
System.out.println("是否是第一个:"+userPageInfo.isIsLastPage());
注解开发
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果封装
@Result({
@Result(column = "",property = ""),
})
@Insert(" insert into user\n" +
" values (#{id}, #{username}, #{password}, #{birthday})")
public void save(User user);
@Result({
@Result(column = "",property = ""),
@Result(
id=true,column = "",property = ""),
property = "",
column = "",
javaType = User.class,
one = @One(select = "mzj.dao.UserMapper.findAll")
)
})
Springz整合Mybatis
用spring产生mapper
App.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<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>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mapper/sqlMapConfig.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper"/>
</bean>
</beans>
sqlMapperConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>
<typeAlias type="Mzj.domain.User" alias="user"/>
<typeAlias type="Mzj.domain.Order" alias="order"/>
<typeAlias type="Mzj.domain.Role" alias="role"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>
</configuration>
SpringBoot
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.6.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<type>pom</type>
</dependency>
测试代码
HelloController
package Mzj.Hellocontroller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello() {
return "hello world!";
}
}
helloSampleController主入口
@SpringBootApplication:springboot应用标注在某个类上说明这个类是SpringBoot的配置类,
SpringBoot就应该运行这个类的main方法来启动SpringBoot应用
package Mzj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class helloSampleController {
public static void main(String[] args) {
SpringApplication.run(helloSampleController.class,args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@SpringBootConfiguration:Spring Boot的配置类
- 标注在某个类上,表示这是一个Spring Boot的配置类。
- @Configuration:配置类上来标注这个注解;
@EnableAutoConfiguration:开启自动配置功能
以前我们需要配置的东西,springboot帮我们自动配置,@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage:自动配置包
-
@Import(AutoConfigurationPackages.Registrar.class)
Spring的底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class 将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面所有组件扫描到spring容器; @Import(AutoConfigurationImportSelector.class)
给容器导入组件 AutoConfigurationImportSelector
导入那些组件的选择器 将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中; 会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是个容器中导入这个场景需要的所有组件,并配置好这些组件; ? [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcJRLprP-1653223158146)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220425012403325.png)] SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())
SpringBoot在启动的时候从类路径下的META-INF/spring.factories获取EnableAutoConfiguration指定的值,这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;
spring-boot-starter-web
spring-boot-starter:spring-boot场景启动器;帮我们导入了web模块正常运行所依赖的组件;
Springboot将所有的功能场景都抽取出来,做成一个个的starts(启动器),只需要在项目里面引入这些starter相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器
yam语法
基本语法
k:(空格)v:表示一对键值对(空格必须有)
以空格的缩进来控制层级关系;只要是左对齐得一列数据,都是一个层级的
server:
port: 8081
path: /hello
值的写法
字面量:普通的值(数字,字符串,布尔)
k:v:字面直接来写;
字符串默认不同加上单引号或者双引号
“”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身香表示的意思
‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
对象、map(属性和值)(键值对)
friends:
lastName: zhangsan
age: 20
行内写法:
firends: { lastName: zhangsan,age: 20}
数组(List、set)
用-值表示数组中的一个元素
pets:
- cat
- dog
行内写法
pets: [cat,dog.pig]
配置文件注入
配置文件
server:
port: 8083
person:
lastName: zhangsan
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: v2}
lists:
- lisi
- liwu
- liliu
dog:
name: 旺财
age: 3
Javabean
package mzj.sping_boot_01.bean;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
@Value获取值和@ConfigurationProperties获取值比较
| @ConfigurationProperties | @Value | 不支持的代码 |
---|
功能 | 批量注入配置文件中的属性 | 一个个指定 | | 松散绑定(松散语法) | 支持 | 不支持 | @Value(“${person.lastName=张三}”) | SpEl(spring表达式) | 不支持 | 支持 | | JSR303数据检验 | 支持 | 不支持 | |
配置-@PropertySource、@ImportResource、@Bean
@ImportResource
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不嫩挂自动是被;
想让spirng的配置文件生效,加载进来;@ImportResource标注在一个配置类上
@ImportResource(locations = {"classpath:beans.xml"})
SpringBoot推荐给容器中添加组件的方式:使用全注解的方式
1、配置类====Spirng配置文件
配置文件占位符
1、随机数
person.lastName=张三${random.uuid}
2、占位符获取之前配置的值,如果没有可以使用:指定默认值
person.dog.name=${person.hello:hello}_旺财
Profile
- Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境
1、多profile文件形式:
文件名字格式
application.properties
application-dev.properties
application-prod.properties
application.properties文件内
server.port=8081
#这里指向文件名字的`-`后面的名字
spring.profiles.active=prod
2、多profile文档块模式
server:
port: 8081
spring:
profiles:
active: dev
---
server:
port: 8083
spring:
config:
activate:
on-profile: dev
---
server:
port: 8084
spring:
config:
activate:
on-profile: prod
3、激活方式:
- 命令行 --spring.porfiles.active=dev
- 配置文件 spring.profiles.active=dev
- jvm参数 -Dspring.profiles.active=dev
配置文件的加载位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h24t67WV-1653223158146)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220427151834291.png)]
server.port=8081
#配置项目于的访问路径
server.servlet.context-path=/boot02
spring.config.location=F:/properties #路径
我们还可以通过spring.config.location来改变默认的配置文件位置
项目打包好以后,我们可以使用命令行参数的形式,启动i项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形式互补配置
加载外部配置顺序
由jar包外向jar内进行寻找
优先加载带profile
application-{profile}.properties
自动配置原理
1)、SpirngBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
2)、@EnableAutoConfiguration 作用:
? 利用AutoConfigurationImportSelector 选择器给容器中导入一些组件?selectImports 这个方法可以看得到;
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
获取候选的配置
SpringFactoriesLoader.loadFactoryNames
扫描所有jar包类路径下 META-INF/spring.factories
把扫描道德这些文件得内容包装成properties对象
从properties获取到`EnableAutoConfiguration.class`类(类名)对应的值,然后把他们添加在容器中
将类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration 的值加入到容器中
test
以HttpEncodingAutoConfiguration 为例子
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
一旦这个配置类生效;这个配置列就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
精髓:
1)、SpringBoot启动会加载大量的自动配置类
2)、我们看我们选哟的功能有没有SpringBoot默认写好的自动配置类;
3)、我们再来看这个自动配置类中到底配置了哪些组件;
4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些书信过的值;
xxxAutoConfiguration:自动配置类;
给容器中添加钻进
xxxProperties:封装配置文件中相关属性;
注解细节
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UIa4X6Qs-1653223158146)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220427204637971.png)]
Conditional扩展注解 | 作用(判断是否满足当前指定条件 ) |
---|
| |
启动debug
debug=true
日志
日志框架
SpringBoot:底层是Spring框架,Spring框架默认使用JCL;
SpringBoot选用还SLFj和logback
SLF4j使用
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pe3AaPY5-1653223158146)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220427210718585.png)]
如何让系统中所有的日志都统一到slf4j;
1、将系统中其他日志框架先排除出去;
2、用中间包来替换原有的日志框架;
3、导入slf4j其他的实现
package mzj.spring_boot_03;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBoot03ApplicationTests {
Logger logger = (Logger) LoggerFactory.getLogger(getClass());
@Test
void contextLoads() {
logger.trace("这个是trace日志");
logger.debug("这是debug日志");
logger.info("这是info日志");
logger.warn("这是warn日志");
logger.error("这是error日志");
}
}
server.port=8080
logging.level.mzj=trace
#logging.path=/spring/log
#不指定路径在当前i项目一下生成springboot.log日志
#可以指定
logging.file.name=F:/springboot.log
# 控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} -%msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss}====[%thread] %-5level %logger{50} -%msg%n
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-viPCSSDx-1653223158147)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220428003319877.png)]
Web开发
Spring Boot对静态资源的映射规则
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
<include>**/*.html</include>
<include>**/*.js</include>
<include>**/*.css</include>
<include>**/*.map</include>
<include>**/*.jpg</include>
<include>**/*.png</include>
<include>**/*.CAB</include>
<include>**/*.ico</include>
<include>**/banner.txt</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4GNriGoN-1653223158147)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220428171447682.png)]
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
1)、所有/webjars/** ,都去classpath:/META-INF/resources/webjars/ 找资源
容器功能
组件添加
@Configuratoin
@EnableConfigurationProperties()自动导入bean
@ConfigurationProperties (prefix = “”)
@SpringBootApplication
相当于
@SpringbootConfiguration
@EnableAutoConfiguration
@ComponentScan()
静态资源配置原理
- SpringBoot启动默认配置加载xxxAutoConfiguration(自动配置类)
- springMVC功能的自动配置类 WebMvcAutoConfiguration,生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = webProperties.getResources();
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
this.mvcProperties.checkConfiguration();
}
资源处理的默认规则
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
spring:
mvc:
hiddenmethod:
filter:
enabled: true
web:
resources:
add-mappings: true
欢迎页的默认规则
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
自定义请求方式
@Configuration(proxyBeanMethods = false)
public class myConfig {
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
return methodFilter;
}
}
请求映射原理
所有的请求映射都在HandlerMapping中
响应json
spring:
mvc:
# 参数内容协商
contentnegotiation:
favor-parameter: true
http://localhost:8080/u?format=json
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
HashMap<String, MediaType> mediaTypes = new HashMap<>();
mediaTypes.put("json",MediaType.APPLICATION_JSON);
ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(mediaTypes);
configurer.strategies(Arrays.asList(strategy));
}
}
}
Thymeleaf
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pt3oHb7J-1653223158147)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220430214550943.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yoAydn99-1653223158147)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220501182413994.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QPYvV37g-1653223158148)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220501183222303.png)]
可以用id选择器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69iwAUWR-1653223158148)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220501185859652.png)]
拦截器
package mzj.spring_boot_web.interceptor;
import lombok.extern.slf4j.Slf4j;
import mzj.spring_boot_web.bean.LoginUser;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Slf4j
public class indexInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("拦截的请求路径是{}", requestURI);
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
String password = (String) session.getAttribute("password");
if (StringUtils.isEmpty(password) || StringUtils.isEmpty(username)) {
session.setAttribute("msg", "还没登录");
System.out.println(request.getContextPath() + "/login");
request.getRequestDispatcher("/loginthtml").forward(request, response);
return false;
} else {
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
package mzj.spring_boot_web.config;
import mzj.spring_boot_web.converter.Userconverter;
import mzj.spring_boot_web.interceptor.indexInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.util.UrlPathHelper;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@Configuration(proxyBeanMethods = false)
public class myConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration interceptorRegistration = registry.addInterceptor(new indexInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/loginthtml","/BootStrap/**","/Jquery/**","/favicon.ico","/login");
}
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
return methodFilter;
}
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new Userconverter());
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
HashMap<String, MediaType> mediaTypes = new HashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(mediaTypes);
HeaderContentNegotiationStrategy headeStrategy = new HeaderContentNegotiationStrategy();
configurer.strategies(Arrays.asList(strategy, headeStrategy));
}
};
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CGvY4pa8-1653223158148)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220502160333230.png)]
文件上传功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GYs33G96-1653223158148)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220502163442276.png)]
spring:
mvc:
hiddenmethod:
filter:
enabled: true
contentnegotiation:
favor-parameter: true
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
server:
port: 8081
package mzj.spring_boot_web.controller.upBook;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
@Slf4j
@Controller
@RequestMapping("/book")
public class UpbookIndex {
@PostMapping("/upbook")
public String upbook(
@RequestParam("photofile") MultipartFile photofile,
@RequestParam("bookfile") MultipartFile bookfile,
HttpSession session
) throws IOException {
log.info("上传的信息:phtotofile={},bookfile={}",photofile.getSize(),bookfile.getSize());
if(!photofile.isEmpty()){
String originalFilename1 = photofile.getOriginalFilename();
photofile.transferTo(new File("F:\\"+originalFilename1));
}
if(!bookfile.isEmpty()){
String originalFilename2 = bookfile.getOriginalFilename();
bookfile.transferTo(new File("F:\\"+originalFilename2));
}
session.setAttribute("msg","成功上传文件");
return "book/bookUp";
}
@GetMapping("/upbookhtml")
public String upBookhtml(Map<String, Object> map,
@RequestHeader Map<String, String> headmap) {
Date date = new Date();
long time = date.getTime();
String date2 = new SimpleDateFormat("yyyy年M月d日 H:m:s").format(time);
map.put("date", date2);
map.put("name", "邵立林");
System.out.println("============================================================================================");
System.out.println("信息头:" + headmap);
System.out.println("============================================================================================");
return "book/bookUp";
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDKGjUsW-1653223158149)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220502181657876.png)]
原生注入
1、使用ServletAPI
2、使用RegistrationBean
启动页面导入扫描组件
@ServletComponentScan(basePackages = "mzj.spring_boot_web")
根据上面原生的来使用
package mzj.spring_boot_web.servlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@Configuration
public class MyRegistConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter, myServlet());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/BootStrap/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean MyListener(){
MyContextListener myContextListener = new MyContextListener();
return new ServletListenerRegistrationBean(myContextListener);
}
}
数据库访问
package mzj.spring_boot_web.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import mzj.spring_boot_web.converter.Userconverter;
import mzj.spring_boot_web.interceptor.indexInterceptor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.util.UrlPathHelper;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@Configuration(proxyBeanMethods = true)
public class myConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean webStatFilter() {
WebStatFilter webStatFilter = new WebStatFilter();
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(webStatFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
filterRegistrationBean.addInitParameter("exclusions","*.js,*jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
@Bean
public ServletRegistrationBean statViewServlet() {
StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");
registrationBean.addInitParameter("loginUsername","root");
registrationBean.addInitParameter("loginPassword","936541");
return registrationBean;
}
@ConfigurationProperties("spring.datasource")
@Bean
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setFilters("stat,wall");
return druidDataSource;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration interceptorRegistration = registry.addInterceptor(new indexInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/loginthtml", "/BootStrap/**", "/Jquery/**", "/favicon.ico", "/login","/sql");
}
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
return methodFilter;
}
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new Userconverter());
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
HashMap<String, MediaType> mediaTypes = new HashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
ParameterContentNegotiationStrategy strategy = new ParameterContentNegotiationStrategy(mediaTypes);
HeaderContentNegotiationStrategy headeStrategy = new HeaderContentNegotiationStrategy();
configurer.strategies(Arrays.asList(strategy, headeStrategy));
}
};
}
}
spring:
datasource:
url: jdbc:mysql:///spring
username: root
password: 936541
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc:
template:
query-timeout: 3
mvc:
hiddenmethod:
filter:
enabled: true
# 参数内容协商
contentnegotiation:
favor-parameter: true
servlet:
multipart:
# 单个文件大小为5MB
max-file-size: 100MB
# 总上传的数据大小5MB
max-request-size: 100MB
# web:
# resources:
# add-mappings: true
# 所有项目的起始路径
#server:
# servlet:
# context-path: /world
server:
port: 8081
error:
path: /error
mybatis
配置版
- 全局配置文件
- SqlSessionFactory:自动配置好了
- SqlSession:自动配置了SqlSessionTemplate组合了SqlSession
- @Import(AutoConfiguredMapperScannerRegistrar.class)
- Mapper:只要我们写的错做MyBatis的接口标准了@Mapper就会被自动扫描进来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zmnhy0h1-1653223158149)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503103552660.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ey7yxALm-1653223158149)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503103610516.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0vu8D2p-1653223158149)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503103620868.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PzJe1DgM-1653223158150)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503103646382.png)]
注解版
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJqcSwdq-1653223158150)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503104826023.png)]
JUnit5
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ug8w3ozy-1653223158150)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503141002521.png)]
package mzj.spring_boot_web;
import org.junit.jupiter.api.*;
import java.util.concurrent.TimeUnit;
@DisplayName("asdas")
public class Testaskd {
@Test
@DisplayName("测试displayname注解1")
void testDisplayName() {
System.out.println(1);
}
@Test
@DisplayName("测试displayname注解2")
void test2(){
System.out.println(2);
}
@Timeout(value = 500,unit = TimeUnit.MILLISECONDS)
@Test
void testTimeout() throws InterruptedException {
Thread.sleep(600);
}
@BeforeEach
void testBefor() {
System.out.println("测试要开始了");
}
@AfterEach
void testAfter(){
System.out.println("测试结束了");
}
@AfterAll
static void testAfterall(){
System.out.println("所有测试都要结束了");
}
@BeforeAll
static void testBeforeAll(){
System.out.println("所有测试都要开始了");
}
@RepeatedTest(9)
@Test
void test3(){
System.out.println(2);
}
}
断言
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eW5cj77T-1653223158150)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503142214026.png)]
参数化测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Sgiqy6e-1653223158150)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503144209855.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EETCWhAI-1653223158151)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503144403718.png)]
自定义starter
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WIa5miU9-1653223158151)(C:\Users\Mzj\AppData\Roaming\Typora\typora-user-images\image-20220503170934024.png)]
|