Spring框架
学过的五种模式:
单例模式,适配器模式,装饰者模式,工厂模式,代理模式
一 、spring
Spring官网:https://spring.io/
Sping:管理java类
面向接口编程:解耦 降低耦合度
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术 Spring : 春天 —>给软件行业带来了春天
优点:
1、Spring是一个开源免费的框架 , 容器 .
2、Spring是一个轻量级的框架 , 非侵入式的 .
3、控制反转 IOC , 面向切面 AOP
4、对事物的支持 , 对框架的支持
·一句话概括:
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。
1 spring的构成
图示: framework:容器 runtime:运行时间
2 Bean管理
• 创建applicationContext.xml
• 配置被管理的Bean
• 获取Bean
。 Bean是管理类的,
Bean的延迟加载:(懒加载):lazy-init
1 init-method : 初始化方法
2 destroy-method : 销毁方法
bean的生命周期
applicationContext.xml:文件及格式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.hisoft.dao.impl.UserDaoImpl"></bean>//管理类
<bean name="userDao" class="com.hisoft.dao.impl.UserDaoImpl"></bean>
<bean class="com.hisoft.dao.impl.UserDaoImpl" init-method="init"></bean>//init-method="init": 初始化方法
<bean id="lazy" class="com.hisoft.dao.impl.UserDaoImpl" lazy-init="true"></bean> //lazy-init="true": 懒加载。默认是false
<bean class="com.hisoft.dao.impl.UserDaoImpl" destroy-method="destroy"></bean>//销毁方法
<bean class="com.hisoft.dao.impl.UserDaoImpl"></bean>
<bean class="com.hisoft.dao.impl.UserDaoImpl"></bean>
<bean class="com.hisoft.dao.impl.UserDaoImpl"></bean>
//可以根据一下方式拿到实例 #号后边是索引,从0开始
// UserDao dao = context.getBean("com.hisoft.dao.impl.UserDaoImpl");
// UserDao dao = context.getBean("com.hisoft.dao.impl.UserDaoImpl#1");
// UserDao dao = context.getBean("com.hisoft.dao.impl.UserDaoImpl#2");
</beans>
测试类:UserDaoImplTest
package com.hisoft.dao;
import com.hisoft.dao.impl.UserDaoImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
//spring容器在启动时会将所有的bean 实例化(默认的) : applicationContext.xml文件里有多少个bean就会实例化多少个对象
// 所有的bean都会有一个实例对象,除非你在某个bean加上懒加载,加了之后会在调用getBean方法的时候才会加载实例化
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Object userDao = context.getBean("lazy");//懒加载在调用getBean方法的时候才会实例化
UserDaoImpl userDao = (UserDaoImpl)context.getBean("userDao");
userDao.save();//Hello Spring...
}
}
需要的jar包依赖 maven配置
<dependencies>
// <!--spring beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
// <!--spring core-->核心
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//ClassPathXmlApplicationContext
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
</dependencies>
3 Bean scopes
1 singleton(默认): spring单例模式
2 prototype: spring多例模式
3 request
4 sessi
//spring单例模式
<bean id="userDao" class="com.xixingit.dao.UserDao" scope="singleton"></bean>
//spring多例模式 spring默认的是单例模式的
<bean id="userDao" class="com.xixingit.dao.UserDao" scope="prototype"></bean>
• request
• sessi
4 Bean的别名
<bean id="userDao" class="com.xixingit.dao.UserDao"></bean>
<alias name="userDao" alias="myUserDao"/>
二 、Spring IOC 与 DI
• IOC 控制反转:
• DI 依赖注入
• 注入的两种方式
IoC 也称为依赖性注射 (DI)。这是一个过程
set注入:
构造方法注入:
对象是由Spring创建的。对象的属性是由Spring容器设置的
这个过程就叫控制反转:IOC:对象由Spring 来创建 , 管理 , 装配 !
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制来创建的,使用Spring后对象是由Spring来创建的
反转:程序本身不能创建对象,而变成被动的接受对象。
IOC是一种编程思想,有主动的编程变成被动的接受
依赖注入:就是利用set方法来进行注入的。
依赖注入(DI)
依赖注入(Dependency Injection): 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
依赖:指Bean对象的创建依赖于容器,由容器来设置和配饰
bean是一个由Spring IoC容器实例化、组装和管理的对象
1.什么是bean
Spring容器负责创建和管理Java对象,这些Java对象成为bean;
Spring容器通过一种叫做:依赖注入的方式来管理bean之间的依赖关系;
使用依赖注入不仅可以为Bean注入普通的属性值,还可以注入其他Bean的引用。
依赖注入是一种优秀的解耦方式,其可以让Bean已配置文件组织在一起,而不是以硬编码的方式耦合在一起;
1.1 理解依赖注入
传统模式的两种做法:
1)原始做法:调用者主动创建被依赖对象,然后再调用被依赖对象的方法;
2)简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取依赖对 象,最后在调用被依赖对象的方法。
注意上面的主动二字,这必然会导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项目升级;
使用Spring框架之后,调用者无需主动获取被依赖对象,调用者只要被动接受Spring容器为调用者的成员变量复制即可
由此可见,使用Spring后,调用者获取被依赖对象
2.Spring容器中的Bean
对于开发者来说:开发者使用Spring框架主要做两件事:1)开发bean 2)配置bean 。 对于
Spring框架来说,他要做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法完成“依赖注入”----这就是IoC的本质。
set注入还是构造方法注入:
使用构造方法注入的理由: • 构造方法注入使用强依赖规定,如果不给足够的参数,对象则无法创建。
• 由于Bean 的依赖都通过构造方法设置了,那么就不用写更多的 set 方法,有助于减少代码量。
使用 set 注入的理由: • 如果Bean有很多的依赖,那么构造方法的参数列表会变的很长。
• 如果一个对象有多种构造方法,构造方法会造成代码量增加。
• 如果构造方法中有两个以上的参数类型相同,那么将很难确定参数的用途。
1 set注入
bean管理的类,配置
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
//<!-- set注入-->
<bean id="userMySql" class="com.hisoft.dao.impl.UserMySqlDao"/>
<bean id="userOracle" class="com.hisoft.dao.impl.UserOracleDao"/>
<bean id="userDao" class="com.hisoft.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.hisoft.service.UserServiceImp">
//<!-- 写法一:(接口,对象)--> ref:需要注入的对象,接口
<property name="userDao" ref="userDao"/>//name属性相当于set方法后面的那一部分部本setUserName,只不过把首字母变为小写
//Bean注入:
<property name="userDao">// : 写法二:(接口,对象)
<bean class="com.hisoft.dao.impl.UserDaoImpl"/>
</property>
//<!--基本类型,集合的set注入-->
//<!--基本类型String,int-->
<property name="name" value="张三"/>
<property name="age" value="12"/>
// <!--list集合-->
<property name="stringList">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
<value>赵六</value>
</list>
</property>
//<!--map集合-->
<property name="map">
<map>
<entry key="键1">
<value>值1</value>
</entry>
<entry key="键2">
<value>值2</value>
</entry>
<entry key="键2">
<value>值2</value>
</entry>
</map>
</property>
//<!--Properties也是一个集合,继承自Hashtable<Object,Object>也是以键值对的形式-->
<property name="properties">
<props>
<prop key="p1键">p1值</prop>
<prop key="p2键">p2值</prop>
</props>
</property>
</bean>
</beans>
java代码:
com.hisoft.dao
UserDao
package com.hisoft.dao;
public interface UserDao {
public void save();
}
UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save....");
}
}
com.hisoft.service
UserServiceImp
import java.util.List;
import java.util.Map
import java.util.Properties;
public class UserServiceImp {
private UserDao userDao;
public String name;
public Integer age;
public List<String> stringList;
public Map<String, Object> map;
public Properties properties;//Properties也是集合,继承了Hashtable<Object,Object>,也是以键值对的形式存值
public void saveAdd(){
userDao.save();
}
//set注入的时候properties中name的值就是set方法后边的userDao名,改为小写
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
test
UserServiceTest
import com.hisoft.service.UserServiceImp;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserServiceImp userService = (UserServiceImp) context.getBean("userService");
userService.saveAdd();//save....
System.out.println(userService.name);//张三
System.out.println(userService.age);//12
System.out.println(userService.stringList);//[张三, 李四, 王五, 赵六]
System.out.println(userService.map);//{键1=值1, 键2=值2}
System.out.println(userService.properties);//{p2键=p2值, p1键=p1值}
}
}
2 构造方法注入
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
// <!--构造方法注入-->
<bean id="bookDao" class="com.hisoft.dao.impl.BookDaoImpl"></bean>
<bean id="bookService" class="com.hisoft.service.BookDaoService">
// <!--4 根据name,也就是参数的名称注入 : 推荐使用这种方式-->
<constructor-arg name="address" value="郑州"/>
<constructor-arg name="name" value="张三"/>
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="stringList">
<list>
<value>阿猫</value>
<value>阿狗</value>
</list>
</constructor-arg>
//<!--3 根据类型注入 不适用于参数是集合的-->
<constructor-arg type="com.hisoft.dao.BookDao" ref="bookDao"/>
<constructor-arg type="java.lang.String" value="张三"/>
<constructor-arg type="java.lang.String" value="郑州"/>
//<!--2 根据参数索引位置注入-->
<constructor-arg index="0" ref="bookDao"/>
<constructor-arg index="1" value="张三"/>
<constructor-arg index="2" value="郑州"/>
<constructor-arg index="3">
<list>
<value>阿猫</value>
<value>阿狗</value>
</list>
</constructor-arg>
//<!--1 根据构造方法的参数名称及类型及顺序,类型相同的话则排在前边的先输出-->
<constructor-arg value="张三"></constructor-arg>
<constructor-arg value="郑州"></constructor-arg>
<constructor-arg ref="bookDao"/>
<constructor-arg>
<list>
<value>阿猫</value>
<value>阿狗</value>
</list>
</constructor-arg>
</bean>
</beans>
com.hisoft.dao
BookDao
public interface BookDao {
public void bookSave();
}
BookDaoImpl
public class BookDaoImpl implements BookDao {
@Override
public void bookSave() {
System.out.println("添加书籍。。。");
}
}
com.hisoft.service
BookDaoService
public class BookDaoService {
private BookDao bookDao;
public BookDaoService(BookDao bookDao, String name,String address, List<String> stringList){
System.out.println(bookDao);//com.hisoft.dao.impl.BookDaoImpl@5aebe890
System.out.println(name);//张三
System.out.println(address);//郑州
System.out.println(stringList.toString());//[阿猫, 阿狗]
this.bookDao = bookDao;
}
public void constructorSave(){
bookDao.bookSave();//添加书籍。。。
}
}
test
BookServiceTest
public class BookServiceTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDaoService bookService = (BookDaoService) context.getBean("bookService");
bookService.constructorSave();
}
}
3 自动注入
autowire的值:
•no
默认值,不进行自动注入
•byName
根据需要注入的属性名称在容器内寻找名称相同的Bean,如果找到就注入,找不到就不注入
•byType
根据需要注入的属性类型在容器找类型相同的Bean,如果找到就注入,找不到就不注入,如果找到多个
类型相同的Bean,则抛出异常
•constructor
构造方法注入先根据byName(参数名称),如果找不到再根据byType(参数类型)找
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="constructor" >//default-autowire=constructor:全局自动注入
// <!--自动注入 局部-->
<bean id="newsDao" class="com.hisoft.dao.impl.NewsDaoImpl"/>
<bean id="newsService" class="com.hisoft.service.NewsService" autowire="constructor"/>
</beans>
service
public class NewsService {
private NewsDao newsDao;
public NewsService(NewsDao newsDao){
this.newsDao = newsDao;
}
public void autoSave(){
newsDao.newsSave();//自动注入。。。
}
public void setNewsDao(NewsDao newsDao) {
this.newsDao = newsDao;
}
}
三 、 Spring Aop
AOP 是能够让我们在不影响原有功能的前提下,为软件横向扩展功能
AOP (面向切面编程)和OOP(面向对象的编程)的区别:AOP是OOP的补充
AOP 的实现原理就是动态代理
1 AOP相关术语
切面(
@Aspect
):
一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。
连接点(Joinpoint
):
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
通知(Advice
):
在切面的某个特定的连接点上执行的动作。其中包括了“around(@Around
)”、“before(@Before
)”和“after(@AfterReturning
) 最后通知(@After
),异常通知(@AfterThrowing
)”等
不同类型的通知:
(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,
并维护一个以连接点为中心的拦截器链
切入点(Pointcut
):
匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行
(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用
AspectJ切入点语法:
引入:
(Introduction
):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-typedeclaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。
目标对象(Target Object):
被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
AOP代理(AOP Proxy)
: AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,
AOP代理可以是JDK动态代理或者CGLIB(基于类的代理)代理。
织入(Weaving)
: 把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时
(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
2 Aop的通知类型
• 前置通知(Before advice)
• 后置通知(After returning advice)
• 异常通知(After throwing advice)
• 最终通知(After (finally) advice)
• 环绕通知(Around Advic
execution(* com.hisoft.dao.impl..*.*(..))
execution(): 表达式主体。
第一个* 表示任何返回值;
第二个* 表示com.hisoft.dao.impl包下的任何class类;
第三个* 表示任何类下的任何方法;
(…)表示方法中有零个或者多个参数
3 AOP Schem验证
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
4 环绕通知
配置文件 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--环绕通知-->
<bean id="myAspect" class="com.hisoft.aspect.AroundAspect"/>
<aop:config>
<aop:aspect ref="myAspect">//跟
<aop:pointcut id="myPointcut" expression="execution(* com.hisoft.dao.impl..*.*(..))"/>
<aop:around method="aroundAdvice" pointcut-ref="myPointcut"></aop:around>
</aop:aspect>
</aop:config>
</beans>
com.hisoft.aspect
AroundAspect
package com.hisoft.aspect;
import com.hisoft.pojo.User;
import org.aspectj.lang.ProceedingJoinPoint;
public class AroundAspect {
public Object aroundAdvice(ProceedingJoinPoint pjp) {
Object object = null;
try {
System.out.println("前置通知。。。");
long startTime = System.currentTimeMillis();
object = pjp.proceed();
long endTime = System.currentTimeMillis();
User user =(User) object;
System.out.println(user.getAge());
System.out.println("后置通知。。。" + (endTime - startTime));
} catch (Throwable th) {
System.out.println("异常通知。。。" + th.getMessage());
th.printStackTrace();
} finally {
System.out.println("最终通知。。。");
}
return object;
}
}
dao, service, test 同下( 5 普通通知)
5 普通通知
配置文件 applicationContext.xml
// <!--aop普通通知-->
<bean id="myAspect" class="com.hisoft.aspect.MyAspect" />
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* com.hisoft.dao.impl..*.*(..))"/>//myPointcut:切入点id
<aop:before method="beforeAdvice" pointcut-ref="myPointcut"></aop:before>
<aop:after-returning method="afterAdvice" pointcut-ref="myPointcut" returning="object"></aop:after-returning>//returning:返回对象
<aop:after-throwing method="exceptionAdvice" pointcut-ref="myPointcut" throwing="exception"></aop:after-throwing>//throwing:异常消息对象 object exception:得和MyAspect类中的一样
<aop:after method="findAdvice" pointcut-ref="myPointcut"></aop:after>
</aop:aspect>
</aop:config>
com.hisoft.aspect
MyAspect
package com.hisoft.aspect;
import com.hisoft.pojo.User;
public class MyAspect {
private long startTime;
private long endTime;
public void beforeAdvice() {
System.out.println("前置通知。。。");
startTime = System.currentTimeMillis();
System.out.println(startTime);
}
public void afterAdvice(Object object){//object是所切入的类里边的方法的返回值
//User user = (User) value;
System.out.println("后置通知。。。" + (((User) object)).getAge());
endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public void exceptionAdvice(Exception exception){//exception是是所切入的类里边的异常信息,如:Hello msg
System.out.println("异常通知。。。" + exception.getMessage());
}
public void findAdvice(){
System.out.println("最终通知。。。");
}
}
dao.imp
NewsDaoImpl
public class NewsDaoImpl implements NewsDao {
@Override
public void newsSave() {
System.out.println("自动注入。。。");
}
@Override
public User findById(){
System.out.println("findById...");
try{
System.out.println(1 / 1);
}catch (Exception e){
throw new RuntimeException("Hello msg");
}
return new User(18);
}
}
service层
public class NewsService {
private NewsDao newsDao;
public void autoSave() {
newsDao.newsSave();//自动注入。。。
}
public User findById(){
User user= newsDao.findById();
return user;
}
public void setNewsDao(NewsDao newsDao) {
this.newsDao = newsDao;
}
}
test
import com.hisoft.service.NewsService;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class NewsServiceTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
NewsService newsService = (NewsService) context.getBean("newsService");
//newsService.autoSave();
newsService.findById();//方法一执行先执行到的是MyAspect(切面)中的前置通知代码,然后才执行的findById()方法
//,接着就到MyAspect后边的代码,后置通知,异常通知,最后通知
}
}
四 、 Annotation :@注解
1 根据Annotation管理Bean,依赖注入
2 根据Annotation管理Aop切面
·applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
//<!--开启基于注解的bean管理 依赖注入,com.hisoft下的所类都纳入注解bean管理->
<context:component-scan base-package="com.hisoft"/>
//<!--开启基于注解的aop切面-->
<aop:aspectj-autoproxy/>
</beans>
3 Bean的注解
@Component
:管理bean 类似组件的,其实三个都可以用,只不过这样区分一下便于管理
@Service:
管理bean service层的
@Repository
: 管理bean 其他java类
@Repository("userDao"):别名
@Lazy(true):
懒加载
@Scope("prototype")
: 多例模式
@PostConstruct:
初始化方法注解
@PreDestroy
: 销毁方法注解
@Aspect :
aop切面
@Pointcut("execution(* com.hisoft.dao..*.*(..))")
:切入方法
@Around("pointcut()")
: aop环绕通知
@Before(value="pointcut()")
: aop前置通知
@AfterReturning(value = "pointcut()",returning = "obj")
:后置童子,obj:返回对象值
@After(value="pointcut()") :
最后通知
@AfterThrowing(value = "pointcut()",throwing = "exception"):
异常通知,异常消息对象
4 JSR 330 Standard Annotation ( jsr330标准注解
)
导入javax.inject.jar(源自JavaEE6)
import javax.inject.Named;
@Named: 管理bean
5 IOC Annotati (·IOC注解
) 依赖注入
@Autowired
: 依赖注入,set依赖注入
@Inject:
依赖注入,set依赖注入
@Resource:
依赖注入,set依赖注入
JSR 33注解
@Inject
@Inject
private UserDao userDao;
@Inject
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
JDR 250注解
@Resource
@Resource
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Resource
private UserDao userDao;
@Autowired
是spring自带的注解,先按byType进行匹配,如果发现找到多个bean,则又按照byName方式(字段名)进行匹配,如果还有多个,则会报异常。可以作用在变量、setter方法、构造函数上。
@Autowired
有个属性为required,可以配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛错;
@Inject
是JSR330中的规范,需要导入javax.inject.jar实现注入,@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named
;@Inject可以作用在变量、setter方法、构造函数上。
@Resource
是JSR250规范的实现,需要导入javax.annotation-api.jar
实现注入。@Resource
是根据名称进行自动装配的,一般会指定一个name属性;@Resource
可以作用在变量、setter方法上。
总例:
com.hisoft.dao
aspect
AroundAspect
package com.hisoft.aspect;
import com.hisoft.entity.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AroundAspect {
@Pointcut("execution(* com.hisoft.dao..*.*(..))")
public void pointcut() {
}
@Around("pointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
Object obj = null;
try {
System.out.println("前置通知。。。");
obj = pjp.proceed();
System.out.println("后置通知。。。" + ((User) obj).getAge());
} catch (Throwable th) {
th.printStackTrace();
System.out.println("异常通知。。。" + th.getMessage());
} finally {
System.out.println("最终通知。。。");
}
return obj;
}
}
MyAspect
package com.hisoft.aspect;
import com.hisoft.entity.User;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect//基于aop切面注解
@Component//纳入bean管理
public class MyAspect {
//切入范围注解,dao层中的所有类
@Pointcut("execution(* com.hisoft.dao..*.*(..))")
public void pointcut(){}
@Before(value="pointcut()")
public void beforeAdvice(){
System.out.println("前置通知。。。");
}
//切入点, returning:返回值
@AfterReturning(value = "pointcut()",returning = "obj")
public void afterAdvice(Object obj){
User user = (User) obj;
System.out.println("后置通知。。。" + user.getAge());//后置通知。。。20
}
@After(value="pointcut()")
public void finallyAdvice(){
System.out.println("最后通知。。。");
}
@AfterThrowing(value = "pointcut()",throwing = "exception")
public void exceptionAdvice(Exception exception){
System.out.println("异常通知。。。" + exception.getMessage());//异常通知。。。Hello Msg
}
}
UserDaoImpl
package com.hisoft.dao.impl;
import com.hisoft.dao.UserDao;
import com.hisoft.entity.User;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Named;
//jdk 17 LTS
@Repository("userDao")//别名
@Lazy(value = true)//懒加载
@Scope(value ="prototype")//多例模式
@Named("userDao")
*************************
@Repository("userDao")//依赖注入的时候根据的就是别名或类名进行注入的,
public class UserDaoImpl implements UserDao {
public UserDaoImpl() {
System.out.println("空的构造方法。。。");
}
public void save() {
System.out.println("用户添加。。。");
}
public User findById() {
try {
int i = 1 / 1;
System.out.println("用户查找。。。");
} catch (Exception e) {
throw new RuntimeException("Hello Msg");
}
return new User(20);
}
@PostConstruct
public void init() {
System.out.println("初始化方法。。。");
}
@PreDestroy
public void destroy() {
System.out.println("销毁方法。。。");
}
}
service层
UserDaoServiceImpl
package com.hisoft.service.impl;
import com.hisoft.dao.UserDao;
import com.hisoft.entity.User;
import com.hisoft.service.UserDaoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.inject.Inject;
@Service(value = "uerService") : 别名的方式,获取bean的时候获取的就是新起的别名
@Service //默认方式,获取bean的时候获取的是类名:userDaoServiceImpl,首字母要小写
public class UserDaoServiceImpl implements UserDaoService {
//三种依赖注入方式,注解加在属性上的话是根据属性名字进行注入的,在接那边写bean注解管理的时候也得写成(如: @repository("userDao"))
@Inject
@Autowired
********************
@Resource
private UserDao userDao;
public void serviceSave(){
userDao.save();
}
public User findById() {
return userDao.findById();
}
//三种注解方法set注入,根据的是参数名字注入
@Inject
@Resource
*******************
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
test
serviceTest
public class serviceTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDaoServiceImpl userDaoService = (UserDaoServiceImpl) context.getBean("userDaoServiceImpl");
//userDaoService.serviceSave();
userDaoService.findById();
}
}
dependencies依赖
pom.xml
<dependencies>
//spring beans包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//spring核心包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//spring 上下文
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--annotation注解-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
//<!--inject注解-->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
//<!-- 基于注解aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//注解
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
//注解@Aspect
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
五 、spring JDBC
1 spring 配置jdbc
实现数据库连接池的几种方式:
HikariCP
,dbcp2:
, c3po , Druid
Druid(德鲁伊) 是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。
基于spring连接数据库需要的依赖:
mysql driver驱动
数据库连接池 :HikariCP
,dbcp2:
, c3po
Spring JDBC
//<!--mysql driver驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
//<!-- 数据库连接池 HikariCP-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
//<!--Spring JDBC JdbcTemplate里边有这个对象相当于之前的DBHelp -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
配置文件:db.properties
db.driverClassName=com.mysql.cj.jdbc.Driver
db.jdbcUrl=jdbc:mysql:///book_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
db.username=root
db.password=123456
配置数据源 方法一(常用)
:applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
//<!-- 基于注解管理bean-->
<context:component-scan base-package="com.hisoft"/>
//<!--配置数据源 方法一 : -->
<context:property-placeholder location="db.properties"/>
<bean id="hikariDateSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="driverClassName" value="${db.driverClassName}"/>
<property name="jdbcUrl" value="${db.jdbcUrl}"/>
</bean>
<!--构建sprong JdbcTemplate: 构建jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="hikariDateSource"/>
</bean>
</beans>
配置数据源 方法二:
//<!--配置数据源 方法二: -->
<bean id="hikariDateSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="jdbcUrl"value="jdbc:mysql:///book_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
2 在Dao中使用JdbcTemplate
·例:
com.hisoft.dao
BookDaoImpl
package com.hisoft.dao.impl;
import com.hisoft.dao.BookDao;
import com.hisoft.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Autowired//通过注解的方式获取jdbcTemplate实例 template:模板
private JdbcTemplate jdbcTemplate;
@Override
public void saveBook(Book book) {
String sql = "insert into book(bookname,author,publisher) values (?,?,?)";
jdbcTemplate.update(sql, book.getBookName(), book.getAuthor(), book.getPublisher());
}
@Override
public Book queryBook(int id) {
String sql = "select id,bookname,author,publisher from book where id = ?";
Book book = (Book) jdbcTemplate.queryForObject(sql, new RowMapperImpl(), id);
return book;
}
@Override
public List<Book> queryBookAll() {
String sql = "select id,bookname,author,publisher from book";
List bookList = jdbcTemplate.query(sql, new RowMapperImpl());
return bookList;
}
@Override
public Long queryCount() {
String sql = "select count(*) from book";
Long bookCount = jdbcTemplate.queryForObject(sql, new RowMapper<Long>() {
/**
* 匿名内部类
*/
@Override
public Long mapRow(ResultSet rs, int i) throws SQLException {
return rs.getLong(1);
}
});
return bookCount;
}
/**
* 内部类,实现一个RowMapper接口
*/
public class RowMapperImpl implements RowMapper {
@Override
public Book mapRow(ResultSet rs, int row) throws SQLException {
int id = rs.getInt("id");
String bookName = rs.getString("bookname");
String author = rs.getString("author");
String publisher = rs.getString("publisher");
Book book = new Book(id, bookName, author, publisher);
return book;
}
}
}
service
接口:
BookService
package com.hisoft.service;
import com.hisoft.entity.Book;
import java.util.List;
public interface BookService {
/**
* 添加书籍
* @param book
*/
void bookSave(Book book);
/**
* 根据id
* 查询书籍
* @param id
* @return
*/
Book queryBook(int id);
/**
* 查询所有书籍
* @return
*/
List<Book> queryBookAll();
/**
* 查询总的的书籍数量
* @return
*/
long queryCount();
}
service接口实现类ipml
@Repository
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
public void bookSave(Book book) {
bookDao.saveBook(book);
}
@Override
public Book queryBook(int id) {
return bookDao.queryBook(id);
}
@Override
public List<Book> queryBookAll() {
return bookDao.queryBookAll();
}
@Override
public long queryCount() {
return bookDao.queryCount();
}
}
test
BookServiceTest
package book;
import com.hisoft.entity.Book;
import com.hisoft.service.impl.BookServiceImpl;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class BookServiceTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookServiceImpl bookServiceImpl = (BookServiceImpl) context.getBean("bookServiceImpl");
//添加数据
Book book = new Book("编程思想","张三","北京出版社");
bookServiceImpl.bookSave(book);
//查询单个书籍
Book book = bookServiceImpl.queryBook(100);
System.out.println(book.toString());
//查询所有书籍
List<Book> bookList = bookServiceImpl.queryBookAll();
for (Book book : bookList ){
System.out.println(book.toString());
}
//查询书籍总数量
long bookCount = bookServiceImpl.queryCount();
System.out.println(bookCount);//39
}
}
六 、 MySQL
mysql外键
图示:
1 存储过程
1.1 什么是存储过程
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。在数据量特别庞大的情况下利用存储过程能达到倍速的效率提升
1.2 数据库存储过程程序
当我们了了解存储过程是什么之后,就需要了解数据库中存在的这三种类型的数据库存储类型程序,如下:
存储过程:
存储过程是最常见的存储程序,存储过程是能够接受输入和输出参数并且能够在请求时被执行的程序单元。
存储函数:
存储函数和存储过程很相像,但是它的执行结果会返回一个值。最重要的是存储函数可以被用来充当标准的 SQL 语句,允许程序员有效的扩展 SQL 语言的能力。
触发器:
触发器是用来响应激活或者触发数据库行为事件的存储程序。通常,触发器用来作为数据库操作语言的响应而被调用,触发器可以被用来作为数据校验和自动反向格式化。
注意:
其他的数据库提供了别的数据存储程序,包括包和类。目前MySQL不提供这种结构。
1.3 为什么要使用存储程序
1 虽然目前的开发中存储程序我们使用的并不是很多,但是不一定就否认它。其实存储程序会为我们使用和管理数据库带来了很多优势:
使用存储程序更加安全。
2 存储程序提供了一种数据访问的抽象机制,它能够极大的改善你的代码在底层数据结构演化过程中的易维护性。
存储程序可以降低网络拥阻,因为属于数据库服务器的内部数据,这相比在网上传输数据要快的多。
3 存储程序可以替多种使用不同构架的外围应用实现共享的访问例程,无论这些构架是基于数据库服务器外部还是内部。
以数据为中心的逻辑可以被独立的放置于存储程序中,这样可以为程序员带来更高、更为独特的数据库编程体验。
4 在某些情况下,使用存储程序可以改善应用程序的可移植性。(在另外某些情况下,可移植性也会很差!)
无参存储过程:
//#声明结束符为//
DELIMITER //
//# 创建存储过程
CREATE PROCEDURE val_fun()
BEGIN
//#声明一个默认值为unknown的val_name局部变量
DECLARE val_name VARCHAR(20) DEFAULT 'unknown';
//# 为局部变量赋值
SET val_name = '张赋值';
//# 查询局部变量
SELECT val_name;
END //
//#调用函数
CALL val_fun()
使用into接收参数
DELIMITER // delimiter:定界符
CREATE PROCEDURE val_into()
BEGIN
//# 定义两个变量存放name和age 设置默认值
DECLARE val_name VARCHAR(20) DEFAULT 'unknown';
DECLARE val_age INT;
// # 查询表中id为1的name和age并放在定义的两个变量中
SELECT username,userage INTO val_name,val_age FROM USER WHERE id = 1 ;
//# 查询两个变量
SELECT val_name,val_age;
END //
//调用函数
CALL val_into() //
SELECT @val_age //
为用户变量赋值
DELIMITER //
CREATE PROCEDURE val_user() //procedure:步骤
BEGIN
//#为用户变量赋值
SET @val_name = '用户名' ;
END //
//#调用函数
CALL val_user() //
//# 查询用户变量
SELECT @val_name //
创建一个入参和出参的存储过程
DELIMITER //
//# 创建一个入参和出参的存储过程
CREATE PROCEDURE val_out(IN val_id INT,OUT val_name VARCHAR(32))
BEGIN
//# 传入参数val_id查询员工返回name值(查询出的name值用出参接收并返回)
SELECT username INTO val_name FROM USER WHERE id = val_id;
END //
//# 调用函数传入参数并声明传入一个用户变量
CALL val_out(2, @'hao') //
//# 查询用户变量
SELECT @'hao' //
2 触发器
一、什么是触发器
触发器(trigger)是MySQL提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作(insert
,delete
,update
)时就会激活它执行。简单理解为:你执行一条sql语句,这条sql语句的执行会自动去触发执行其他的sql语句。
二、触发器的作用
可在写入数据表前,强制检验或转换数据。
触发器发生错误时,异动的结果会被撤销。
部分数据库管理系统可以针对数据定义语言(DDL)使用触发器,称为DDL触发器。
可依照特定的情况,替换异动的指令 (INSTEAD OF)。
三、触发器创建的四要素
监视地点(table)
监视事件(insert、update、delete)
触发时间(after、before)
触发事件(insert、update、delete)
四、触发器的使用语法
语法:
before/after: 触发器是在增删改之前执行,还是之后执行
delete/insert/update: 触发器由哪些行为触发(增、删、改)
on 表名: 触发器监视哪张表的(增、删、改)操作
触发SQL代码块: 执行触发器包含的SQL语句
//#声明结束符
DELIMITER //
CREATE TRIGGER //触发器名
BEFORE|AFTER DELETE|INSERT|UPDATE
ON 表名 FOR EACH ROW
BEGIN
//触发SQL代码块;
END //
原文链接:https://blog.csdn.net/weixin_44170221/article/details/106710257
触发器执行在update操作之后
//#声明结束符
DELIMITER //
//#创建触发器,触发器的名称为t3
CREATE TRIGGER t3
//# 触发器执行在update操作之后
AFTER INSERT
//# 监视t_1表
ON t_1
FOR EACH ROW
BEGIN
//# 触发执行sql语句
UPDATE USER SET userage = userage + 1 WHERE id = 1 ;
END //
触发器执行在insert操作之后
DELIMITER //
CREATE TRIGGER t3 //trigger:触发器
//# 触发器执行在insert操作之后
AFTER INSERT
ON t_1
FOR EACH ROW
BEGIN
UPDATE USER SET userage = userage + 2 WHERE id = 2;
END //
触发器执行在delete操作之前
DELIMITER //
CREATE TRIGGER t4
//# 触发器执行在delete操作之前
BEFORE DELETE
ON t_1
FOR EACH ROW
BEGIN
UPDATE USER SET userage = userage + 3 WHERE id = 4;
END //
3 视图
一 、视图概述
视图是由数据库中的一个表或多个表导出的虚拟表,是一种虚拟存在的表,方便用户对数据的操作。
·1 视图的概念
视图是一个虚拟表,是从数据库中一个或多个表中导出来的表,其内容由查询定义。同真实表一样,视图包含一系列带有名称的列和行数据。但是,数据库中只存放了视图的定义,而并没有存放视图中的数据。这些数据存放在原来的表中。使用视图查询数据时,数据库系统会从原来的表中取出对应的数据。因此,视图中的数据是依赖于原来的表中的数据的。一旦表中的数据发生改变,显示在视图中的数据也会发生改变。
视图是存储在数据库中的查询的SQL语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,例如,员工信息表,可以用视图只显示姓名、工龄、地址,而不显示社会保险号和工资数等;另一个原因是可使复杂的查询易于理解和使用。
2
视图的作用
对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其他数据库的一个或多个表,或者其他视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。视图的作用归纳为如下几点。
1、简单性
看到的就是需要的。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件。
2、安全性
视图的安全性可以防止未授权用户查看特定的行或列,使有权限用户只能看到表中特定行的方法,如下:
(1)``在表中增加一个标志用户名的列。
(2)建立视图,使用户只能看到标有自己用户名的行。
(3)把视图授权给其他用户。
3、逻辑数据独立性
视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,程序一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。视图可以在以下几个方面使程序与数据独立。
(1)如果应用建立在数据库表上,当数据库表发生变化时,可以在表上建立视图,通过视图屏蔽表的变化,从而使应用程序可以不动。
(2)如果应用建立在数据库表上,当应用发生变化时,可以在表上建立视图,通过视图屏蔽应用的变化,从而使数据库表不动。
(3)如果应用建立在视图上,当数据库表发生变化时,可以在表上修改视图,通过视图屏蔽表的变化,从而使应用程序可以不动。
(4)如果应用建立在视图上,当应用发生变化时,可以在表上修改视图,通过视图屏蔽应用的变化,从而使数据库可以不动。
为什么使用视图:?
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询,而自身不包含任何数据
1.重用SQL语句
2.简化复杂的SQL操作
3使用表的组成部分而不是整个表
4.保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限
5.更改数据格式和表示
视图的规则与限制
1.与表一样,视图必须唯一命名
2.在一个数据库中,可以创建的视图数目没有限制
3.视图可以嵌套,即可以利用从其他视图中查询出来的数据构建新的视图
4.order by可以用在视图中,但如果从该视图检索数据的select中也含有order by,那么该视图中的Order by将会被覆盖
5视图不能索引,也不能有关联的触发器或默认值
6.视图和表可以一起使用,例如编写一条联接表和视图的查询
视图的更新:
1 对视图进行insert update delete将会影响其基表,因为视图中不包含任何数据
2 不是所有视图都可以更新
2.1
含有分组(group by 和 having)
2.2
. 联接查询
2.3
. 子查询
2.4
.聚合函数
2.5
. DISTINCT
不是迫不得已,不要对视图进行更新操作,因为效率低。视图主要用于查询
原文链接:https://blog.csdn.net/pan_junbiao/article/details/86132535
创建一个视图表
//view_book:视图表名称
CREATE OR REPLACE VIEW view_book
AS
//查询出来的语句存入视图表view_book中
SELECT id,bookname,author FROM book;
·
创建视图同时,指定属性清单(也就是新的列名)
CREATE OR REPLACE VIEW view1(a_id,a_bookname,author)
AS
SELECT id , bookname,author FROM book;
修改视图
ALTER VIEW view_book
AS
SELECT id,bookname,author FROM book WHERE id IN(SELECT id FROM book);
删除视图
DROP VIEW IF EXISTS view_view1;
4 事务
在MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务
事务处理可以用来维护数据库的完整性,保证成批的SQL操作要么完全执行,要么完全不执行
事务用来管理:insert
、update
、delete
语句
关于事务的术语:
事务(transaction
):指一组SQL语句
回滚(rollback
):指撤销指定SQL语句的过程
提交(commit
):指将未存储的SQL语句结果写入到数据库中
保留点(savepoint
):指事务处理中设置的临时占位符,可以对它进行回滚
事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应归回滚,何时提交
事务的四个特征(ACID属性)
1 原子性(Atomic):组成事务的处理语句组成了一个逻辑单元,这是最小的执行单位
2 一致性(Consistent):在事务处理执行之前和之后,数据是一致的
3 一致性(Consistent):在事务处理执行之前和之后,数据是一致的
4 隔离性(Isolated):一个事务的处理对另一个事务没有影响
5 持续性(Durable):当事务处理成功后,其结果在数据库中被永久记录下来
START TRANSACTION : 开始事务
回滚事务:指撤销指定sql语句的过程
//#回滚事务:指撤销指定sql语句的过程
//#开始事务
START TRANSACTION;
DELETE FROM USER WHERE id = 4;
//#事务回滚
ROLLBACK;
提交事务(commit):指将未存储的SQL语句结果写入到数据库中
//#提交(commit):指将未存储的SQL语句结果写入到数据库中
START TRANSACTION;
DELETE FROM USER WHERE id = 4;
//#事务提交
COMMIT;
保留点(savepoint):指事务处理中设置的临时占位符,可以对它进行回滚
//#保留点(savepoint):指事务处理中设置的临时占位符,可以对它进行回滚
START TRANSACTION;
DELETE FROM USER WHERE id = 4;
//#声明一个保留点
SAVEPOINT sl;
DELETE FROM USER WHERE id = 5 ;
//#回滚到保留点
ROLLBACK TO sl;
4 Spring事务管理
Spring事务出现在service层
需要的依赖,事务的管理依赖于spring jdbc
,以为jdbc是连接数据库的,需要导入的事务管理的包spring-tx
pom.xml
// <!--Spring JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--spring事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"//事务管理的schema验证
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
//<!-- 基于注解管理bean-->
<context:component-scan base-package="com.hisoft"/>
// <!--配置数据源 方法一 : -->
<context:property-placeholder location="db.properties"/>//连接池配置文件名及所在地
<bean id="hikariDateSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="driverClassName" value="${db.driverClassName}"/>
<property name="jdbcUrl" value="${db.jdbcUrl}"/>
</bean>
//<!--构建sprong JdbcTemplate: 构建jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="hikariDateSource"/>
</bean>
//<!-- 开启基于注解管理事务-->
<tx:annotation-driven transaction-manager="transactionManger"/>
//<!--jdbc事务管理器,开启事务管理依赖于jdbc包,因为jdbc是连接数据库的,事务主要作用在service层,加入事务:保证操作的完整是,数据的一致性-->
<bean id="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="hikariDateSource"/>
</bean>
</beans>
在service层事务管理:
1 、 事务加在service层,如果在下层(dao层)发生异常并向上抛的话这时候service层事务管理就会生效,进行回滚操作如果异常是发生在service的上层(controller层),则service层事务管理不会生效。
2 、 事务管理只能管理RuntimeException(运行时异常),如果是其他的异常则不会生效,要想其他异常事务管理也生效的话则:
在service层的service类上加: ·@Transactional(noRollbackFor = Exception)
3 、 在service层里注入bookDao,则BookDao也纳入了事务管理,只要在dao层或service层里发生了异常事务管理就会生效
4 、 ·@Transactional(readOnly = true)
: 该方法指定事务是只读的,也就是说如果报异常可也不影响查询,只查并不影响数据的一致性,提高读取的效率,优化性能
package com.hisoft.service.impl;
import com.hisoft.dao.BookDao1;
import com.hisoft.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
//@Transactional(noRollbackFor = Exception): 其他异常事务管理也生效
@Transactional//加入事务,可读可写事务
public class ServiceBook {
@Autowired
private BookDao1 bookDao1;
/**
* 事务管理的添加书籍
* @param book
*/
public void bookSave1(Book book) {
bookDao1.saveBook(book);
}
//该方法指定事务是之读的,也就是谁如果报异常可也不影响查询,只4查并不影响数据的一致性,提高读取的效率,优化性能
@Transactional(readOnly = true)
public Book findBook(int id) {
return bookDao1.queryBook(id);
}
}
自定义异常
package com.hisoft.exception;
public class MyException extends RuntimeException {
public MyException(){}
public MyException (String msg){
super(msg);
}
public MyException(String msg,Throwable throwable){
super(msg,throwable);
}
}
4 spring中的事务
4.1 Spring事务隔离级别
1、 DEFAULT 使用数据库默认隔离级别
2、 READ_UNCOMMITTED 允许读取尚未提交的数据。可能导致脏读、幻读或不可重复读。
3 、READ_COMMITTED 允许从已经提交的并发事务读取。可以防止脏读,但依然会出现幻读和不可重复读。
4、 REPEATABLE_READ 对相同字段的多次读取结果是相同的,除非数据被当前事务改变。可以防止脏读和不可重
复读,但幻读依然出现。
5、 SERIALIZABLE 完全符合ACID的隔离级别,确保不会发生脏读,幻读和不可重复读。
6、 脏读:一个事务读取到另一个事务没有提交到的数据。
7、 不可重复读:在同一事务中,多次读取同一数据返回的结果不同。
8、 幻读:一个事务读取到另一个事务已经提交的事务。
4.2 Spring事务传播属性
1、 REQUIRED 业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务中,
否则自己创建一个事务。(大部分情况下使用)
2 、NOT-SUPPORTED 声明方法需要事务。如果方法没有关联到一个事务,容器会为它开启一个事务,如果方法在
一个事务中被调用,该事务将会被挂起,在方法调用结束后 ,原先的事务会恢复执行。
3、 REQUIREDNEW 业务方法必须在自己的事务中运行。一个新的事务将被启动,而且如果有一个事务正在运行,
则将这个事务挂起,方法运行结束后,新事务执行结束,原来的事务恢复运行。
4、 MANDATORY 该方法必须运行在一个现有的事务中,自身不能创建事务,如果方法在没有事务的环境下被调用,
则会抛出异常。
5、 SUPPORTS 如果该方法在一个事务环境中运行,那么就在这个事务中运行,如果在事务范围外调用,那么就在
一个没有事务的环境下运行。
6、 NEVER 表示该方法不能在有事务的环境下运行,如果在有事务运行的环境下调用,则会抛出异常
7、 NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按照REQUIRED事
务方式执行。该事务可以独立的进行提交或回滚,如果回滚不会对外围事务造成影响
4.3 基于XML配置的事务
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*"/>
<tx:method name="edit*"/>
<tx:method name="find*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.xixingit.service..*.*(..))" id="myPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref=“myPointcut” />
</aop:config>
4.4 spring中的事务
spring 中的事务 遇到异常时会自动回滚,前提是:异常必须是运行时异常。 @Transactional(rollbackFor=Exception.class) 如果目标方法出现该异常,事务回滚
在方法上也可以添加@Transactional,会覆盖类上的事务
查询的方法建议加上@Transactional(readOnly=true)(只读事务),提高效率
配置隔离级别和传播属性
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED)
七 、springMVC
classpath:SpringMVC.xml
如果这个也没有解决的话,可以看一下自己的SpringMVC文件是不是在类加载路径,即src目录下
1 JSP+Servlet+JavaBean
2 SpringMVC
Spring的web框架围绕
DispatcherServlet
设计。DispatcherServlet
的作用是将请求分发到不同的处理器
Springmvc架构原理解析:
1
发起请求到前端控制器(DispatcherServlet)
2
前端控制器请求HandlerMapping查找 Handler,可以根据xml配置、注解进行查找
3
处理器映射器HandlerMapping向前端控制器返回Handler
4
前端控制器调用处理器适配器去执行Handler
5
处理器适配器去执行Handler
6
Handler执行完成给适配器返回ModelAndView
7
处理器适配器向前端控制器返回ModelAndView,ModelAndView是springmvc框架的一个底层对象,包括 Model和view
8
前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)
9
视图解析器向前端控制器返回View
10
前端控制器进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request域
11
前端控制器向用户响应结果
组件:
1、
前端控制器DispatcherServlet(不需要程序员开发)作用接收请求,应结果,相当于转发器,中央处理器。有了DispatcherServlet减少了其它组件之间的耦合度。
2、
处理器映射器HandlerMapping(不需要程序员开发)作用:根据请求的url查找Handler
3、
处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
4、
处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、
视图解析器View resolver(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6、视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
原文链接:https://blog.csdn.net/Number_oneEngineer/article/details/82775419
3 配置中央(前端)控制器
需要的依赖:
springMVC字符集过滤器
web.xml
//<!--spring 字符集过滤器-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置mvc前置控制器
如图:
web.xml
//<!-- 配置springMVC前置控制器-->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>//1.设置servlet的加载优先级别 2.在启动容器时是否加载该servlet
2.在启动容器时是否加载该servlet
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
mvc-servlet.xml
:→ 命名规则:-servlet.xml固定,mvc:就是 <servlet-name>的名称,得一致
<?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: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
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
//<!--开启扫描com.xxx.controller包-->
<context:component-scan base-package="com.hisoft.controller"/>
//<!--开启使用注解-->
<mvc:annotation-driven/>
//<!--配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
访问静态资源jquery,css
mvc-servlet.xml
//<!--访问静态资源,不加这个配置的话static包里边的东西访问不到,controller层以为请求的是像自己写的那中链接,*代表什么什么包下的东西-->
<mvc:resources mapping="/static/**" location="/static/"/>
//不用经过controller层直接走想要的页面
<mvc:view-controller path="/file" view-name="upload"/>
配置视图解析器
//<!--配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hisoft</groupId>
<artifactId>srpingMVC</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
// <!-- spring beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
// <!--spring core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
// <!--spring context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
//<!--springMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//spring-webmvc
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//jstl
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
//javax.servlet-api 获取HttpServletRequest
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
//<!--json-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
// <!-- spring aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
//<!--mysql driver-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
//<!--数据库连接池-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
//<!--spring jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
//<!--spring 事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
</dependencies>
//<!-- 配置maven项目的tomcat-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
// <!-- 指定端口 -->
<port>8081</port>
// <!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
4 Controller层
@RequestMapping注解
是用来映射一个URL到一个类或一个特定的方处理法上。
BookController
package com.hisoft.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller//controller的纳入spring bean管理注解
public class BookController {
@PostMapping("/book/save")
public String save(){
System.out.println("Hello MvcWeb");
return "book";
}
@RequestMapping(value = "/book/save",method = RequestMethod.GET) //通过注解指定是GET请求
public String save(@RequestParam(required = false ,defaultValue = "15",value = "uid") Integer id){
//@RequestParam:请求参数(required:默认的参数。false:url参数想传就传,不想传就不传 true:一定得传方法括号对应要的参数
// 注:参数得是包装类类型的。 defaultValue:默认传过来的参数为15
// value:url传过来的参数名称为uid时,自动把uid的值赋给id。例:localhost:8801/book/save?uid=20,则此时id的值就为20)
System.out.println("Hello MvcWeb" + id);
return "book";//通过return的方式跳转的到book.jsp,基于mvc-servlet.xml配置配置文件中的视图解析器来实现的
}
}
所在包,依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hisoft</groupId>
<artifactId>srpingMVC</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!-- spring beans-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!--springMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--json-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
<!-- spring aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<!--mysql driver-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!--数据库连接池-->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
<!--spring jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring 事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--commons-fileupload 文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--java mail-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!--在springMVC中的email依赖,发送邮件,也需要java mail-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--log4j 日志依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<!-- 配置maven项目的tomcat-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 指定端口 -->
<port>8081</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
import javax.servlet.http.HttpServletRequest;
package com.hisoft.controller;
import com.hisoft.domain.Book;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.ArrayList;
import java.util.List;
url传参
//url传参
@GetMapping("/book/update/{id}/{p:\\d+}")//{id}是url携带过来的参数,例:localhost:8081/book/update/2/3 {id}这样使用时得加上@PathVariable注解
public String update(@PathVariable(value = "id") Integer uid, @PathVariable Integer p) {
System.out.println("uid:" + uid + "\n" + "p:" + p);//uid=2(这是传过来是id=2然后id赋值给uid得到的),p=3
return "book";
}
接受表单的值,表单请求
//接受表单的值,表单请求
@PostMapping("/book/save")
public String save(Book book, String ISBN) {
System.out.println(ISBN);//Hello 传过类的值参数写的是Book则可以自动将值封装到book对象中,前提是form表单的name值和Book实体类中属性一样
System.out.println("bookName:" + book.getBookName() + "\n" + "author:" + book.getAuthor());//bookName:三国演义, author罗贯中
return "book";
}
Model带参跳转到相应文件夹下的jsp与获取HttpServletResponse
带值跳转的要跳转的页面 方法一:
//带值跳转的要跳转的页面 方法一:
@GetMapping("/book/list")//model是spring mvc框架提供的
public String findAll(Model model, HttpServletRequest request) {
request.getParameter("bookName");//这也可以获取到表单name属性值,前提导:javax.servlet-api依赖
List<String> bookList = new ArrayList<>();
bookList.add("张三");
bookList.add("李四");
bookList.add("王五");
model.addAttribute("bookList", bookList);//可以将值一键值对的形式带到页面去
return "list";
}
ModelAndView带参跳转到相应文件夹下的jsp
带值跳转的要跳转的页面 方法二:
//带值跳转的要跳转的页面 方法二:
@GetMapping("/book/list1")
public String findAll(ModelMap modelMap) {
List<String> bookList = new ArrayList<>();
bookList.add("Rose");
bookList.add("Jack");
bookList.add("Jerry");
modelMap.addAttribute("bookList", bookList);
return "list";
}
类似重定向带参
,重定向到方法和RedirectAttributes
//跳转到views包下得子包card里的card.jsp
@GetMapping("/book/card")
public String card(){
return "card/card";
}
//类似重定向带参
@GetMapping("book/del/{id}")//{id}
public String delete(@PathVariable Integer id, RedirectAttributes redirectAttributes){
System.out.println(id);
redirectAttributes.addFlashAttribute("msg","删除成功!");//将msg值带到book.jsp页面
return "redirect:/book/card";//不能直接重定向到jsp页面,得经过另外的servlet
}
给页面刷出文本text值·
//给页面刷出文本值
@GetMapping("/text")
public @ResponseBody String respText(){
return "Hello" ;
}
返回 json… @ResponseBody
给页面刷出(传)json类型的集合
//依赖jar包:jackson-databind
//给页面刷出(传)json类型的集合
@GetMapping(value = "/jsonList",produces = "application/json;charset=utf-8")
public @ResponseBody List<Book> findAllJson(){
Book book = new Book();
book.setBookName("编程思想");
book.setAuthor("张三");
List<Book> bookList = new ArrayList<>();
bookList.add(book);
return bookList;
}
5 springMVC上传文件
mvc-servlset.xml
配置
文件上传解析器
其他映射
//<!--文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="300000"/>
</bean>
//<!--其他映射,可以不用经过controller层直接去到你想要的页面,path是路径,访问的路径,也就是说在地址栏上范文/file就可以走到upload.jsp这个页面,view-name是jsp名称-->
<mvc:view-controller path="/file" view-name="upload"/>
需要依赖commons-fileupload
包
// <!--commons-fileupload 文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
controller层
FileUploadController
package com.hisoft.controller.commons;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
@RequestMapping("/file")
public class FileUploadController {
@PostMapping("/upload")
public String fileUpload(String desc, String[] hobby, MultipartFile[] files) {
System.out.println(desc);//普通文本描述值
for (String ho : hobby) {//爱好name值
System.out.println(ho);
}
//文件类型
for (MultipartFile file : files) {
String contentType = file.getContentType(); //获取文件的类型
String propertyName = file.getName();//获取file控件的name属性值
String fileName = file.getOriginalFilename();//获取上传的文件名称
long size = file.getSize();//获取文件的大小
System.out.println(contentType + "\n" + fileName);
//截取文件类型后缀名
int index = fileName.lastIndexOf(".");
String suffix = null;
if (index != -1) {
suffix = fileName.substring(index);
//保证文件名的唯一性
String prefix = UUID.randomUUID().toString();
//拼接新文件名称
String newFileName = prefix + suffix;
//构建目录路径
File filePath = new File("d:/img/" + newFileName);
try {
file.transferTo(filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "upload";
}
}
WEB-INF/views/upload.jsp
<form action="/file/upload" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="desc">
<br>
文件上传<input type="file" name="files"><br>
文件上传<input type="file" name="files">
<br>
请选择你的爱好:
篮球:<input type="checkbox" name="hobby" value="篮球">
足球:<input type="checkbox" name="hobby" value="足球">
排球:<input type="checkbox" name="hobby" value="排球">
<br>
<input type="submit" value="点击上传">
</form>
6 spring mail电子邮件发送
applicationContext
发送邮件配置
//<!--发送邮件配置-->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.163.com"/>
<property name="username" value="yang7email@163.com"/>
<property name="password" value="ROBQTYBQTQVSQVNW"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
所需依赖
spring-context-support
和
//<!--java mail-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
//<!--在springMVC中的email依赖,发送邮件,也需要java mail-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
controller层
package com.hisoft.controller.commons;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class EmailController {
@Autowired
private JavaMailSender javaMailSender;//JavaMailSenderImpl类实现的一个接口
@GetMapping("/send/email")
public String sendEmail() {
//新开一个线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("yang7email@163.com");//从哪开始发送
message.setSubject("电子邮件主题");//发送主题
message.setTo("1064289281@qq.com");//发送到哪
message.setText("恭喜你中奖了!");
javaMailSender.send(message);
}
});
thread.start();
return "";
}
}
7 拦截器
拦截器配置
拦截器不会拦截js,css,只会拦截controller层的
mvc-servlet.xml
//<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.hisoft.interceptor.LoginInterceptor">
<property name="uris">//为uris集合注入值
<list>
<value>/user/login</value>//放行的路径
<value>/user/message</value>
</list>
</property>
</bean>
</mvc:interceptor>
</mvc:interceptors>
//<!--异常解析器-->
<bean id="handlerExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="com.hisoft.exception.LoginException">redirect:/user/message</prop>
</props>
</property>
</bean>
自定义拦截器类·LoginInterceptor
package com.hisoft.interceptor;
import com.hisoft.domain.User;
import com.hisoft.exception.LoginException;
import org.springframework.http.converter.json.SpringHandlerInstantiator;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
//继承HandlerInterceptorAdapter 类
public class LoginInterceptor extends HandlerInterceptorAdapter {
//在mvc-servlet.xml配置文件中进行bean管理
private List<String> uris;
public void setUris(List<String> uris) {
this.uris = uris;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
User curredUser = (User) session.getAttribute("curredUser");
String uri = request.getRequestURI();
if (uris.contains(uri)) {//contains():包含,如果uris里包含uri就true,uris的值是通过set注入在配置文件里设定的
return true;//拦截器放行
} else {
if (curredUser != null) {//登录验证判断
return true;
} else {
//法一:自定义异常,配置文件里的异常解析器一检测到就会重定向到在配置文件里定义的路径,throw异常之后后面就可以不用return了,直接代码不往下走了
throw new LoginException();
//法二:也可直接从这重定向
/* response.sendRedirect("/user/message");
return true;*/
}
}
}
}
自定义异常
public class LoginException extends RuntimeException {
public LoginException() {
}
public LoginException(String msg) {
super(msg);
}
public LoginException(String msg, Throwable th) {
super(msg, th);
}
}
controller层
LoginController
package com.hisoft.controller.login;
import com.hisoft.dao.UserDao;
import com.hisoft.domain.User;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class LoginController {
//org.apache.log4j.Logger 日志,logger:记录器
Logger logger = Logger.getLogger(LoginController.class);
@Autowired
private UserDao userDao;
@PostMapping("/login")
public String loginUser(User user, HttpSession session) {
User curredUser = userDao.findUser(user);
session.setAttribute("curredUser", curredUser);
return "redirect:/book/list";
}
@GetMapping("/login")
public String loginUser() {
return "user/login";
}
@GetMapping("/message")
public String loginMsg() {
logger.info("跳转登录的页面!");
return "user/msg";
}
}
web层
WEB-INF/views/user/login.jsp
<form action="/user/login" method="post">
<input type="text" name="userName" placeholder="请输入你的用户名">
<br>
<input type="password" name="password" placeholder="请输入你的密码">
<br>
<input type="submit" value="登录">
</form>
WEB-INF/views/user/msg.jsp
<body>
<h3>你还未登录,请先<a href="/user/login">登录</a>再操作!</h3>
</body>
8 日志
日志级别: 小→大
debug→info→warn→eorror→fatal:严重错误
log4j 日志依赖
//<!--log4j 日志依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
在控制台打印日志信息
将日志信息写到外部文件
以天为单位生成日志文件
log4j.properties
//在控制台打印日志信息
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%p](%d)---%l---%m\r\n
//#log4j.rootLogger=error,A1
log4j.rootLogger=DEBUG,A1
//#将日志信息写到外部文件D:/logs/log.log中
log4j.appender.fout=org.apache.log4j.FileAppender
log4j.appender.fout.layout=org.apache.log4j.PatternLayout
log4j.appender.sout.layout.ConversionPattern=[%p](%d)---%l---%m\r\n
log4j.appender.fout.file=D:/logs/log.log
log4j.rootLogger=DEBUG,A1,fout
//#以天为单位生成日志文件
log4j.appender.B=org.apache.log4j.DailyRollingFileAppender
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=[%p](%d)---%l---%m\r\n
log4j.appender.B.DatePattern='.'yyyy-MM-dd
log4j.appender.B.file=D:/logs/logMsg.log
log4j.rootLogger=DEBUG,A1,fout,B
各符号代表的含义:
%m
输出代码中指定的消息
%p
输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r
输出自应用启动到输出该log信息耗费的毫秒数
%c
输出所属的类目,通常就是所在类的全名
%t
输出产生该日志事件的线程名
%n
输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
%d
输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,
比如:%d{yyy MMM dd HH:mm:ss , SSS}
% l
输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。
输出日志小案例
import org.apache.log4j.Logger;//注意所导的包得是这个
@Controller
@RequestMapping("/user")
public class LoginController {
//org.apache.log4j.Logger 日志,logger:记录器
Logger logger = Logger.getLogger(LoginController.class);
@GetMapping("/message")
public String loginMsg() {
logger.info("跳转登录的页面!");//打印日志信息,根据properties文件决定日志在哪记录
return "user/msg";
}
}
根据日志级别存放的不同的位置
log4j.appender.fout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fout.layout=org.apache.log4j.PatternLayout
log4j.appender.fout.layout.ConversionPattern=[%p](%d)---%l--%m\r\n
log4j.appender.fout.DatePattern='.'yyyy-MM-dd
log4j.appender.fout.Threshold=INFO
log4j.appender.fout.file=C:/logs/x.log
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%p](%d)---%l--%m\r\n
log4j.rootLogger=DEBUG, A1,fout
根据包输出日志信息
log4j.appender.fout=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fout.layout=org.apache.log4j.PatternLayout
log4j.appender.fout.layout.ConversionPattern=[%p](%d)---%l--%m\r\n
log4j.appender.fout.DatePattern='.'yyyy-MM-dd
log4j.appender.fout.file=C:/logs/x.log
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%p](%d)---%l--%m\r\n
log4j.logger.com.google=ERROR,fout
log4j.rootLogger=DEBUG, A1