Spring基础笔记
【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"
xsi: schemaLocation= " http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd" >
</ beans>
【2】Spring IoC/DI
IoC(Inversion of Control)中文名称:控制反转。也被称为DI(dependency injection )依赖注入。属于同一件事情的两个名称。
IoC/DI是指一个过程:对象的创建仅仅通过Spring容器负责,Spring容器可以通过对象的构造方法或工厂方法进行实例化对象。在创建对象过程中,如果对象需要依赖其他对象,也可以直接在Spring容器中注入到当前对象。
整个过程中对象本身在容器中控制自己的实例化(所以叫做控制反转),通过构造方法或setter方法把依赖对象注入到自己(所以又叫做依赖注入)
【3】容器
容器(Container):放置所有管理对象的对象。其本质是在容器对象里面有一个全局Map对象,map对象中放置所有被管理的对象。Spring中容器是指ApplicationContext接口及子接口或实现类。
【3】Beans
容器中所有被管理的对象称为beans。如果单说其中一个对象可称为bean
【4】Bean实例化
有两种方式
方式一:
通过构造方法进行实例化。默认使用无参构造。在XML中通过<bean>的class属性指定类的全限定路径,然后就可以实例化对象。
注意:无参构造方法如果不存在,将抛出异常BeanCreationException
方式二:
通过工厂进行实例化。可以通过静态工厂和实例工厂进行实例化
如下所示:工厂的创建方法属于构造方法进行实例化,Student.class 的实例化是通过工厂模式进行的实例化
<?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 = " staticFactoryStudent" class = " com.bjsxt.factory.StudentStaticFactory" factory-method = " newInstance" > </ bean>
< bean id = " stuInstanceFactory" class = " com.bjsxt.factory.StudentInstanceFactory" > </ bean>
< bean id = " instanceFactoryStudent" factory-bean = " stuInstanceFactory" factory-method = " getInstance" > </ bean>
</ beans>
package com. bjsxt. factory ;
import com. bjsxt. pojo. Student ;
public class StudentInstanceFactory {
private Student student = new Student ( ) ;
public StudentInstanceFactory ( ) {
System . out. println ( "创建了学生实例工厂对象。" ) ;
}
public Student getInstance ( ) {
return student;
}
}
package com. bjsxt. factory ;
import com. bjsxt. pojo. Student ;
public class StudentStaticFactory {
private static Student student = new Student ( ) ;
public StudentStaticFactory ( ) {
System . out. println ( "学生静态工厂创建对象" ) ;
}
public static Student newInstance ( ) {
return student;
}
}
@Test
public void testStaticFactory ( ) {
ApplicationContext context =
new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
Student student = context. getBean ( "staticFactoryStudent" , Student . class ) ;
System . out. println ( student) ;
}
@Test
public void testInstanceFactory ( ) {
ApplicationContext context =
new ClassPathXmlApplicationContext ( "classpath:applicationContext.xml" ) ;
Student student = context. getBean ( "instanceFactoryStudent" , Student . class ) ;
System . out. println ( student) ;
}
【5】属性注入
有两种方式
方式一:
构造注入(Constructor-based Dependency Injection):通过构造方法给bean的属性赋值。所以要求bean的类中必须提供对应参数的构造方法
方式二:
设值注入,又称setter注入(Setter-based Dependency Injection):通过Bean的setter方法赋值。所以要求Bean中属性必须提供setter方法
<?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 = " student" class = " com.bjsxt.pojo.Student" >
< constructor-arg name = " id" value = " 10" > </ constructor-arg>
< constructor-arg type = " java.lang.String" value = " 李四" > </ constructor-arg>
< constructor-arg index = " 2" value = " 30" > </ constructor-arg>
</ bean>
< bean id = " student" class = " com.bjsxt.pojo.Student" >
< property name = " id" value = " 100" > </ property>
< property name = " name" value = " 王五" > </ property>
< property name = " age" value = " 25" > </ property>
</ bean>
</ beans>
public class People {
private int id;
private String name;
private int age
public People ( ) {
}
public People ( int id, String name, int age) {
this . id = id;
this . name = name;
this . age = age;
}
}
@Test
public void testConstructor ( ) {
ApplicationContext context =
new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
Student student = context. getBean ( "student" , Student . class ) ;
System . out. println ( student) ;
}
【6】不同属性类型注入方式
< bean id = " peo7" class = " com.bjsxt.pojo.People" >
< property name = " hover" >
< set>
< value> 看尚学堂视频</ value>
< value> 听尚学堂老师讲课</ value>
</ set>
</ property>
</ bean>
< bean id = " peo7" class = " com.bjsxt.pojo.People" >
< property name = " subjects" >
< list>
< value> java</ value>
< value> 前端</ value>
</ list>
</ property>
</ bean>
< bean id = " peo7" class = " com.bjsxt.pojo.People" >
< property name = " teachers" >
< array>
< value> 高淇</ value>
< value> 张佳明</ value>
</ array>
</ property>
</ bean>
< bean id = " peo7" class = " com.bjsxt.pojo.People" >
< property name = " phone" >
< map>
< entry key = " 姓名" value = " 18612345678" > </ entry>
</ map>
</ property>
</ bean>
< bean id = " peo7" class = " com.bjsxt.pojo.People" >
< property name = " info" >
< props>
< prop key = " name" > 值</ prop>
</ props>
</ property>
</ bean>
< bean id = " peo7" class = " com.bjsxt.pojo.People" >
< property name = " phone" >
< null> </ null>
</ property>
</ bean>
@Test
public void testConstructor ( ) {
ApplicationContext context =
new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
Student student = context. getBean ( "student" , Student . class ) ;
System . out. println ( student) ;
}
【7】自动注入
<?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 = " default" >
< bean id = " people" class = " com.bjsxt.pojo.People" autowire = " no" >
< property name = " id" value = " 10" />
< property name = " name" value = " 张三" />
</ bean>
< bean id = " idCard" class = " com.bjsxt.pojo.IdCard" >
< property name = " id" value = " 1" />
< property name = " idNo" value = " 220502200201011111" />
< property name = " address" value = " 赛蒂工业园" />
</ bean>
< bean id = " card" class = " com.bjsxt.pojo.IdCard" >
< property name = " id" value = " 2" />
< property name = " idNo" value = " 220502200201011112" />
< property name = " address" value = " 赛蒂工业园2" />
</ bean>
</ beans>
package com. bjsxt. pojo ;
import java. io. Serializable ;
import java. util. Objects ;
public class People implements Serializable {
private Integer id;
private String name;
private IdCard idCard;
public People ( ) {
System . out. println ( "无参数构造方法" ) ;
}
public People ( IdCard idCard) {
System . out. println ( "(IdCard idCard)参数构造方法" ) ;
this . idCard = idCard;
}
public People ( Integer id, String name, IdCard idCard) {
System . out. println ( "(Integer id, String name, IdCard idCard) 参数构造方法" ) ;
this . id = id;
this . name = name;
this . idCard = idCard;
}
@Override
public String toString ( ) {
return "People{" +
"id=" + id +
", name='" + name + '\'' +
", idCard=" + idCard +
'}' ;
}
@Override
public boolean equals ( Object o) {
if ( this == o) return true ;
if ( o == null || getClass ( ) != o. getClass ( ) ) return false ;
People people = ( People ) o;
return Objects . equals ( id, people. id) &&
Objects . equals ( name, people. name) &&
Objects . equals ( idCard, people. idCard) ;
}
@Override
public int hashCode ( ) {
return Objects . hash ( id, name, idCard) ;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public IdCard getIdCard ( ) {
return idCard;
}
public void setIdCard ( IdCard idCard) {
this . idCard = idCard;
}
}
【8】Bean标签的scope属性
scope控制的是Bean的有效范围,有六种属性:
- singleton:默认值。bean是单例的,每次获取Bean都是同一个对象
- prototype:每次获取bean都重新实例化
- request:每次请求重新实例化对象,同一个请求中多次获取时单例的
- session:每个会话内bean是单例的
- application:整个应用程序对象内bean是单例的
- websocket:同一个websocket对象内对象是单例的
注意:
里面的singleton和prototype在Spring最基本的环境中就可以使用,不需要web环境。但是里面的request、session、application、websocket都只有在web环境才能使用。
Spring 中 Bean是否是线程安全的?
如果bean的scope是单例的,bean不是线程安全的
如果bean的scope是prototype,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
https://www.springframework.org/schema/beans/spring-beans.xsd"
>
< bean id = " people" class = " com.bjsxt.pojo.People" autowire = " no" scope = " singleton" lazy-init = " false" init-method = " init"
destroy-method = " init" >
< property name = " id" value = " 10" />
< property name = " name" value = " 张三" />
</ bean>
</ beans>
@Test
public void testScope ( ) {
ApplicationContext context = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
System . out. println ( "spring容器创建完毕" ) ;
People people = context. getBean ( "people" , People . class ) ;
System . out. println ( people) ;
}
【9】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
https://www.springframework.org/schema/beans/spring-beans.xsd"
>
< bean id = " people" class = " com.bjsxt.pojo.People" init-method = " init" destroy-method = " init" >
< property name = " id" value = " 10" />
< property name = " name" value = " 张三" />
</ bean>
</ beans>
package com. bjsxt. pojo ;
import java. io. Serializable ;
import java. util. Objects ;
public class People implements Serializable {
private Integer id;
private String name;
private IdCard idCard;
public People ( ) {
System . out. println ( "无参数构造方法" ) ;
}
public People ( IdCard idCard) {
System . out. println ( "(IdCard idCard)参数构造方法" ) ;
this . idCard = idCard;
}
public People ( Integer id, String name, IdCard idCard) {
System . out. println ( "(Integer id, String name, IdCard idCard) 参数构造方法" ) ;
this . id = id;
this . name = name;
this . idCard = idCard;
}
@Override
public String toString ( ) {
return "People{" +
"id=" + id +
", name='" + name + '\'' +
", idCard=" + idCard +
'}' ;
}
@Override
public boolean equals ( Object o) {
if ( this == o) return true ;
if ( o == null || getClass ( ) != o. getClass ( ) ) return false ;
People people = ( People ) o;
return Objects . equals ( id, people. id) &&
Objects . equals ( name, people. name) &&
Objects . equals ( idCard, people. idCard) ;
}
@Override
public int hashCode ( ) {
return Objects . hash ( id, name, idCard) ;
}
public void init ( ) {
System . out. println ( "初始化方法运行。" ) ;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
System . out. println ( "setId方法运行" ) ;
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
System . out. println ( "setName方法运行" ) ;
this . name = name;
}
public IdCard getIdCard ( ) {
return idCard;
}
public void setIdCard ( IdCard idCard) {
System . out. println ( "setIdCart方法运行:" + idCard) ;
this . idCard = idCard;
}
}
【10】单例模式
package com. bjsxt. singleton ;
public class Singleton {
private static Singleton singleton = new Singleton ( ) ;
private Singleton ( ) { }
public static Singleton getInstance ( ) {
return singleton;
}
}
package com. bjsxt. singleton ;
class Singleton2 {
private static Singleton2 singleton2;
private Singleton2 ( ) {
}
public static Singleton2 getInstance ( ) {
if ( singleton2 == null ) {
synchronized ( Singleton2 . class ) {
if ( singleton2== null ) {
singleton2 = new Singleton2 ( ) ;
}
}
}
return singleton2;
}
}
【11】Spring 循环注入问题
在Spring IoC/DI使用过程中,可能出现循环注入的情况。当两个类都是用构造注入时,没有等当前类实例化完成就需要注入另一个类,而另一个类没有实例化完整还需要注入当前类,所以这种情况是无法解决循环注入问题的的。会出现BeanCurrentlyInCreationException异常。
如果两个类都使用设值注入且scope为singleton的就不会出现问题,可以正常执行。因为单例默认下有三级缓存(DefaultSingletonBeanRegistry),可以暂时缓存没有被实例化完成的Bean。但是如果两个类的scope都是prototype依然报BeanCurrentlyInCreationException
循环注入的多个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
https://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire = " constructor" >
< bean id = " a" class = " com.bjsxt.pojo.A" scope = " singleton" >
< property name = " aName" value = " aaa" > </ property>
< property name = " b" ref = " b" > </ property>
</ bean>
< bean id = " b" class = " com.bjsxt.pojo.B" scope = " singleton" >
< property name = " bName" value = " bbb" > </ property>
< property name = " a" ref = " a" > </ property>
</ bean>
</ beans>
package com. bjsxt. pojo ;
import java. io. Serializable ;
import java. util. Objects ;
public class A implements Serializable {
private String aName;
private B b;
public A ( String aName, B b) {
this . aName = aName;
this . b = b;
}
public A ( ) {
System . out. println ( "A无参构造运行" ) ;
}
@Override
public String toString ( ) {
return "A{" +
"aName='" + aName + '\'' +
'}' ;
}
@Override
public boolean equals ( Object o) {
if ( this == o) return true ;
if ( o == null || getClass ( ) != o. getClass ( ) ) return false ;
A a = ( A ) o;
return Objects . equals ( aName, a. aName) &&
Objects . equals ( b, a. b) ;
}
@Override
public int hashCode ( ) {
return Objects . hash ( aName, b) ;
}
public String getaName ( ) {
return aName;
}
public void setaName ( String aName) {
this . aName = aName;
}
public B getB ( ) {
return b;
}
public void setB ( B b) {
System . out. println ( "a.setB运行" ) ;
this . b = b;
}
}
package com. bjsxt. pojo ;
import java. io. Serializable ;
import java. util. Objects ;
public class B implements Serializable {
private String bName;
private A a;
public B ( String bName, A a) {
this . bName = bName;
this . a = a;
}
public B ( ) {
System . out. println ( "B无参构造运行" ) ;
}
@Override
public String toString ( ) {
return "B{" +
"bName='" + bName + '\'' +
'}' ;
}
@Override
public boolean equals ( Object o) {
if ( this == o) return true ;
if ( o == null || getClass ( ) != o. getClass ( ) ) return false ;
B b = ( B ) o;
return Objects . equals ( bName, b. bName) &&
Objects . equals ( a, b. a) ;
}
@Override
public int hashCode ( ) {
return Objects . hash ( bName, a) ;
}
public String getbName ( ) {
return bName;
}
public void setbName ( String bName) {
this . bName = bName;
}
public A getA ( ) {
return a;
}
public void setA ( A a) {
System . out. println ( "b.setA运行" ) ;
this . a = a;
}
}
package com. bjsxt. test ;
import com. bjsxt. pojo. A ;
import com. bjsxt. pojo. B ;
import org. junit. Test ;
import org. springframework. context. ApplicationContext ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
public class TestCyc {
@Test
public void testCyc ( ) {
ApplicationContext context = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
System . out. println ( "ApplicationContext创建结束" ) ;
A a = context. getBean ( "a" , A . class ) ;
System . out. println ( a) ;
System . out. println ( a. getB ( ) ) ;
System . out. println ( "==================================================" ) ;
B b = context. getBean ( "b" , B . class ) ;
System . out. println ( b) ;
System . out. println ( b. getA ( ) ) ;
}
}
【12】BeanFactory和ApplicationContext
BeanFactory是Spring中的顶级接口,接口中定了Spring容器最基本功能。是Spring IoC的最核心接口。
BeanFactory最常用实现类是XmlBeanFactory
从Spring 3.1 版本开始,使用DefaultListableBeanFactory和XMLBeanDefinitionReader替代了XmlBeanFactory
无论是使用哪个写法,都可以发现BeanFactory是在真正getBean的时候才去实例化的
ApplicationContext是BeanFactory的子接口。所以要比BeanFactory的功能更加强大,除了BeanFactory的功能,还包含了:
- AOP 功能
- 国际化(MessageSource)
- 访问资源,如URL和文件(ResourceLoader)
- 消息发送机制(ApplicationEventPublisher)
- Spring集成Web时的WebApplicationContext
在使用时ApplicationContext时多使用ClassPathXmlApplicationContext
ApplicationContext是在加载文件后立即创建Bean。可以通过lazy-init属性进行控制,让bean懒加载
package com. bjsxt. test ;
import com. bjsxt. pojo. A ;
import org. junit. Test ;
import org. springframework. beans. factory. BeanFactory ;
import org. springframework. beans. factory. support. DefaultListableBeanFactory ;
import org. springframework. beans. factory. xml. XmlBeanDefinitionReader ;
import org. springframework. beans. factory. xml. XmlBeanFactory ;
import org. springframework. core. io. FileSystemResource ;
public class TestBeanFactory {
@Test
public void testBeanFactory2 ( ) {
BeanFactory factory = new DefaultListableBeanFactory ( ) ;
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader (
( ( DefaultListableBeanFactory ) factory)
) ;
reader. loadBeanDefinitions (
new FileSystemResource ( "C:\\ideaWorkspace\\sj125_spring\\sj125_spring_2\\src\\main\\resources\\applicationContext.xml" )
) ;
System . out. println ( "===================================" ) ;
A a = factory. getBean ( "a" , A . class ) ;
System . out. println ( a) ;
}
@Test
public void testBeanFactory1 ( ) {
FileSystemResource resource =
new FileSystemResource ( "C:\\ideaWorkspace\\sj125_spring\\sj125_spring_2\\src\\main\\resources\\applicationContext.xml" ) ;
BeanFactory beanFactory = new XmlBeanFactory ( resource) ;
System . out. println ( "BeanFactory创建结束" ) ;
A a = beanFactory. getBean ( "a" , A . class ) ;
System . out. println ( a) ;
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
Object teacher = applicationContext. getBean ( "teacher" ) ;
}
}
【13】Spring整合Web
Spring框架整合Web应用需要的配置如下:
1. web.xml必要配置
配置一个Listener,去读取Spring的配置文件,并创建ApplicationContext。
把创建好的容器ApplicationContext保存到ServletContext作用域(application)中。
这个Listener是Spring框架提供的,在spring-web.jar包中。org.springframework.web.context.ContextLoaderListener
在这个Listener中,会主动的读取web.xml配置文件中的上下文初始化参数。<context-param>。参数的名字是 contextConfigLocation,
参数的值就是spring配置文件的位置。如果spring配置文件在类路径下,可以增加前缀 classpath:
监听器,启动后,读取初始化参数contextConfigLocation,并创建ApplicationContext接口的子接口类型WebApplicationContext的容器对象。
创建后的容器,保存在ServletContext变量作用域中,attributeName是WebApplicationContext类的全命名.ROOT 。
2. spring配置(暂时是必要的)
使用bean标签,配置需要让spring容器管理的那些对象。
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://xmlns.jcp.org/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version = " 4.0" >
< context-param>
< param-name> contextConfigLocation</ param-name>
< param-value> classpath:applicationContext.xml</ param-value>
</ context-param>
< listener>
< listener-class> org.springframework.web.context.ContextLoaderListener</ listener-class>
</ listener>
</ web-app>
<?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 = " default" >
< bean id = " userService" class = " com.bjsxt.service.impl.UserServiceImpl" > </ bean>
</ beans>
package com. bjsxt. controller ;
import com. bjsxt. pojo. User ;
import com. bjsxt. service. UserService ;
import org. springframework. web. context. WebApplicationContext ;
import org. springframework. web. context. support. WebApplicationContextUtils ;
import javax. servlet. ServletConfig ;
import javax. servlet. ServletException ;
import javax. servlet. annotation. WebServlet ;
import javax. servlet. http. HttpServlet ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. IOException ;
@WebServlet ( "/login" )
public class LoginServlet extends HttpServlet {
private UserService userService;
@Override
public void init ( ServletConfig config) throws ServletException {
super . init ( config) ;
userService =
WebApplicationContextUtils . findWebApplicationContext ( config. getServletContext ( ) )
. getBean ( "userService" , UserService . class ) ;
}
@Override
protected void service ( HttpServletRequest req, HttpServletResponse resp) throws ServletException , IOException {
String username = req. getParameter ( "username" ) ;
String password = req. getParameter ( "password" ) ;
User user = userService. login ( username, password) ;
if ( user == null ) {
resp. sendRedirect ( "/fail.jsp" ) ;
}
resp. sendRedirect ( "/success.jsp" ) ;
}
}
【14】Spring整合Mybatis
spring整合MyBatis
所谓的整合MyBatis,就是让Spring容器去创建SqlSessionFactory,并且为Mapper接口做接口绑定。
一旦整合成功。Spring容器中存在SqlSessionFactory,可以基于工厂创建SqlSession,可以基于会话getMapper获取接口绑定对象。
Spring整合MyBatis后,自动提交事务。这是spring框架修改了mybatis的默认事务管理机制。实际上是mybatis-spring.jar修改了mybatis框架的
默认事务管理机制。
1. 写spring配置文件。必要
2. 也可以写mybatis.cfg.xml配置文件,可选。 一般只有设置plugin的时候,写这个配置文件。
<?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.bjsxt</ groupId>
< artifactId> springmybatis</ artifactId>
< version> 1.0-SNAPSHOT</ version>
< packaging> war</ packaging>
< dependencies>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> 3.5.9</ version>
</ dependency>
< dependency>
< groupId> mysql</ groupId>
< artifactId> mysql-connector-java</ artifactId>
< version> 8.0.28</ version>
</ dependency>
< dependency>
< groupId> log4j</ groupId>
< artifactId> log4j</ artifactId>
< version> 1.2.17</ version>
</ dependency>
< dependency>
< groupId> com.fasterxml.jackson.core</ groupId>
< artifactId> jackson-databind</ artifactId>
< version> 2.8.11.6</ version>
</ dependency>
< dependency>
< groupId> javax.servlet</ groupId>
< artifactId> javax.servlet-api</ artifactId>
< version> 4.0.1</ version>
< scope> provided</ scope>
</ dependency>
< dependency>
< groupId> javax.servlet.jsp</ groupId>
< artifactId> javax.servlet.jsp-api</ artifactId>
< version> 2.3.3</ version>
< scope> provided</ scope>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-web</ artifactId>
< version> 5.3.16</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> 5.3.16</ version>
</ dependency>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis-spring</ artifactId>
< version> 2.0.7</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-jdbc</ artifactId>
< version> 5.3.16</ version>
</ dependency>
</ dependencies>
< build>
< resources>
< resource>
< directory> src/main/java</ directory>
< includes>
< include> **/*.xml</ include>
</ includes>
< filtering> true</ filtering>
</ resource>
< resource>
< directory> src/main/resources</ directory>
< filtering> true</ filtering>
</ resource>
</ resources>
< plugins>
< plugin>
< groupId> org.apache.tomcat.maven</ groupId>
< artifactId> tomcat7-maven-plugin</ artifactId>
< version> 2.2</ version>
< configuration>
< path> /bjsxt</ path>
< port> 8081</ port>
</ configuration>
</ plugin>
</ plugins>
</ build>
</ project>
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://xmlns.jcp.org/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version = " 4.0" >
< context-param>
< param-name> contextConfigLocation</ param-name>
< param-value> classpath:applicationContext.xml</ param-value>
</ context-param>
< listener>
< listener-class> org.springframework.web.context.ContextLoaderListener</ listener-class>
</ listener>
</ web-app>
<?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 = " default" >
< bean id = " dataSource" class = " org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name = " driverClassName" value = " com.mysql.cj.jdbc.Driver" > </ property>
< property name = " url" value = " jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai" > </ property>
< property name = " username" value = " root" > </ property>
< property name = " password" value = " root" > </ property>
</ bean>
< bean id = " sqlSessionFactory" class = " org.mybatis.spring.SqlSessionFactoryBean" >
< property name = " dataSource" ref = " dataSource" > </ property>
< property name = " configLocation" value = " classpath:mybatis.cfg.xml" > </ property>
</ bean>
< bean id = " scanner" class = " org.mybatis.spring.mapper.MapperScannerConfigurer" >
< property name = " sqlSessionFactoryBeanName" value = " sqlSessionFactory" > </ property>
< property name = " basePackage" value = " com.bjsxt.mapper" > </ property>
</ bean>
< bean id = " userService" class = " com.bjsxt.service.impl.UserServiceImpl" >
< property name = " userMapper" ref = " userMapper" > </ property>
</ bean>
</ beans>
在resources文件夹的目录下直接新建mybatis.cfg.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>
< typeAliases>
< package name = " com.bjsxt.pojo" />
</ typeAliases>
</ configuration>
package com. bjsxt. pojo ;
public class User {
private int id;
private String username;
private String password;
public User ( ) {
}
public User ( int id, String username, String password) {
this . id = id;
this . username = username;
this . password = password;
}
public int getId ( ) {
return id;
}
public void setId ( int id) {
this . id = id;
}
public String getUsername ( ) {
return username;
}
public void setUsername ( String username) {
this . username = username;
}
public String getPassword ( ) {
return password;
}
public void setPassword ( String password) {
this . password = password;
}
}
package com. bjsxt. mapper ;
import com. bjsxt. pojo. User ;
import org. apache. ibatis. annotations. Select ;
public interface UserMapper {
@Select ( "select * from user where username=#{username} and password=#{password}" )
User selectByUser ( User user) ;
}
package com. bjsxt. service. impl ;
import com. bjsxt. mapper. UserMapper ;
import com. bjsxt. pojo. User ;
import com. bjsxt. service. UserService ;
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
public void setUserMapper ( UserMapper userMapper) {
this . userMapper = userMapper;
}
@Override
public User login ( User user) {
return userMapper. selectByUser ( user) ;
}
}
package com. bjsxt. servlet ;
import com. bjsxt. pojo. User ;
import com. bjsxt. service. UserService ;
import org. springframework. web. context. WebApplicationContext ;
import org. springframework. web. context. support. WebApplicationContextUtils ;
import javax. servlet. ServletConfig ;
import javax. servlet. ServletException ;
import javax. servlet. annotation. WebServlet ;
import javax. servlet. http. HttpServlet ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. IOException ;
import java. io. PrintWriter ;
@WebServlet ( "/login" )
public class LoginServlet extends HttpServlet {
UserService userService;
@Override
public void init ( ServletConfig config) throws ServletException {
WebApplicationContext wac = WebApplicationContextUtils . getWebApplicationContext ( config. getServletContext ( ) ) ;
userService = wac. getBean ( "userService" , UserService . class ) ;
}
@Override
protected void service ( HttpServletRequest req, HttpServletResponse resp) throws ServletException , IOException {
req. setCharacterEncoding ( "utf-8" ) ;
String username = req. getParameter ( "username" ) ;
String password = req. getParameter ( "password" ) ;
User user = new User ( 0 , username, password) ;
User result = userService. login ( user) ;
resp. setContentType ( "text/html;charset=utf-8" ) ;
PrintWriter out = resp. getWriter ( ) ;
if ( result!= null ) {
out. print ( "登录成功" ) ;
} else {
out. print ( "登录失败" ) ;
}
}
}
package com. bjsxt ;
import com. bjsxt. pojo. User ;
import com. bjsxt. service. UserService ;
import org. springframework. context. ApplicationContext ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
public class TestSpringMyBatis {
public static void main ( String [ ] args) {
ApplicationContext context = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
UserService userService = context. getBean ( "userService" , UserService . class ) ;
System . out. println ( "=============================================================" ) ;
String [ ] beanNames = context. getBeanDefinitionNames ( ) ;
for ( String beanName : beanNames) {
Object bean = context. getBean ( beanName) ;
System . out. println ( beanName + " - " + bean. getClass ( ) . getName ( ) + " - " + bean) ;
}
System . out. println ( "=============================================================" ) ;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="login" mehtod="post">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
【15】Maven 占位符/ EL 表达式 / Spring 占位符
Maven 占位符主要用于在 Maven 构建过程中替换配置文件中的占位符为实际的值。如: 在 pom.xml 中配置资源过滤,并在资源文件中使用占位符
EL 表达式主要用于 Java EE 技术中,用来访问和操作 JavaBean 的属性,尤其在 JSP 页面和 JSF 表达式语言中常见。
Spring 占位符用于在 Spring 应用程序中引用外部化的配置值,可以用于 XML 配置文件或者通过 @Value 注解注入到 Spring Bean 中
< build>
< resources>
< resource>
< directory> src/main/resources</ directory>
< filtering> true</ filtering>
</ resource>
</ resources>
</ build>
# config.properties
database.url=${db.url}
database.username=${db.username}
# database.properties
database.url=jdbc:mysql://localhost:3306/mydb
database.username=admin
database.password=admin123
< context: property-placeholder location = " classpath:database.properties" />
< bean id = " dataSource" class = " org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name = " url" value = " ${database.url}" />
< property name = " username" value = " ${database.username}" />
< property name = " password" value = " ${database.password}" />
</ bean>
mport org. springframework. beans. factory. annotation. Value;
import org. springframework. stereotype. Component ;
@Component
public class MyComponent {
@Value ( "${database.url}" )
private String dbUrl;
@Value ( "${database.username}" )
private String dbUsername;
}
【16】Spring常用注解
注解名称 解释 @Component 实例化Bean,默认名称为类名首字母变小写。支持自定义名称 @Repository @Component子标签。作用和@Component一样。用在持久层 @Service @Component子标签。作用和@Component一样。用在业务层 @Controller @Component子标签。作用和@Component一样。用在控制器层 @Configuration @Component子标签。作用和@Component一样。用在配置类 @Autowired 自动注入。默认byType,如果多个同类型bean,使用byName(默认通过属性名查找是否有同名的bean,也可以通过@Qualifier(“bean名称”),执行需要注入的Bean名称) @Resource 非Spring注解。默认byName,如果没找到,使用byType。
<?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"
default-autowire = " default" >
< context: component-scan
base-package = " com.bjsxt.dao.impl,com.bjsxt.dao,com.bjsxt.*,com.bjsxt" > </ context: component-scan>
</ beans>
【17】@Configuration 和 @Bean
package com. bjsxt. config ;
import com. bjsxt. dao. UserDao ;
import com. bjsxt. dao. impl. UserDaoImpl ;
import com. bjsxt. service. UserService ;
import com. bjsxt. service. impl. UserServiceImpl ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. beans. factory. annotation. Qualifier ;
import org. springframework. context. annotation. Bean ;
import org. springframework. context. annotation. Configuration ;
@Configuration
public class MyConfiguration {
@Bean
public UserDao userDao ( ) {
System . out. println ( "使用Configuration创建UserDao对象" ) ;
return new UserDaoImpl ( ) ;
}
@Bean ( "userService" )
public UserService suibian ( ) {
System . out. println ( "使用Configuration创建UserService对象" ) ;
UserServiceImpl userService = new UserServiceImpl ( ) ;
userService. setUserDao ( userDao ( ) ) ;
return userService;
}
}
【18】@Autowired
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
public UserServiceImpl ( UserRepository userRepository) {
this . userRepository = userRepository;
}
@Autowired
public void setUserRepository ( UserRepository userRepository) {
this . userRepository = userRepository;
}
@Override
public void createUser ( String username) {
System . out. println ( "Creating user: " + username) ;
}
}
【19】@ContextConfigration
package com. bjsxt. test ;
import com. bjsxt. 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 ( "classpath:applicationContext.xml" )
public class TestSpringTest {
@Autowired
private UserService userService;
@Test
public void testUserService ( ) {
userService. add ( ) ;
}
}
【20】AOP
Aspect:切面
join point: 切入点。也称目标方法。即对哪个方法做扩展、做增强
Pointcut:切点。即表达式,通过表达式说明哪些方法做扩展、做增强(join point 的批量处理)
Advice:通知,增强内容
AOP Proxy:代理。Spring支持JDK动态代理和cglib动态代理两种方式,可以通过proxy-target-class=true把默认的JDK动态代理修改为Cglib动态代理
【21】Schema-based
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-aop</ artifactId>
< version> 5.3.16</ version>
</ dependency>
< dependency>
< groupId> org.aspectj</ groupId>
< artifactId> aspectjweaver</ artifactId>
< version> 1.9.9.1</ version>
</ dependency>
<?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"
default-autowire = " default" >
< bean id = " userService" class = " com.bjsxt.service.impl.UserServiceImpl" > </ bean>
< bean id = " beforeAdvice" class = " com.bjsxt.advice.MyBeforeAdvice" > </ bean>
< bean id = " afterReturningAdvice" class = " com.bjsxt.advice.MyAfterReturningAdvice" > </ bean>
< bean id = " aroundAdvice" class = " com.bjsxt.advice.MyAroundAdvice" > </ bean>
< bean id = " throwsAdvice" class = " com.bjsxt.advice.MyThrowsAdvice" > </ bean>
< bean id = " beforeAndAfter" class = " com.bjsxt.advice.MyBeforeAndAfterAdvice" > </ bean>
< aop: config>
< aop: pointcut id = " firstPointCut"
expression = " execution( void com.bjsxt.service.impl.UserServiceImpl.sayHello() )" />
< aop: pointcut id = " secondPointCut"
expression = " execution( java.lang.String com.bjsxt.service.UserService.showInfo() )" />
< aop: pointcut id = " allPointCut" expression = " execution( * com.bjsxt.service.*.*(..) )" />
< aop: advisor advice-ref = " beforeAdvice" pointcut-ref = " firstPointCut" > </ aop: advisor>
< aop: advisor advice-ref = " beforeAdvice" pointcut-ref = " secondPointCut" > </ aop: advisor>
< aop: advisor advice-ref = " beforeAdvice"
pointcut = " execution( java.lang.String com.bjsxt.service.UserService.sayHello( java.lang.String ) )" > </ aop: advisor>
< aop: advisor advice-ref = " afterReturningAdvice" pointcut-ref = " allPointCut" > </ aop: advisor>
< aop: advisor advice-ref = " aroundAdvice" pointcut-ref = " allPointCut" > </ aop: advisor>
< aop: advisor advice-ref = " throwsAdvice" pointcut-ref = " allPointCut" > </ aop: advisor>
< aop: advisor advice-ref = " beforeAndAfter" pointcut-ref = " allPointCut" > </ aop: advisor>
</ aop: config>
</ beans>
package com. bjsxt. advice ;
import org. springframework. aop. MethodBeforeAdvice ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before ( Method method, Object [ ] args, Object target) throws Throwable {
System . out. println ( "方法前置通知,运行的方法名是:" + method. getName ( ) + ", 运行方法的参数是:" + Arrays . toString ( args) + ", 这个方法依托的对象是:" + target) ;
}
}
package com. bjsxt. advice ;
import com. bjsxt. pojo. User ;
import org. springframework. aop. AfterReturningAdvice ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning ( Object returnValue, Method method, Object [ ] args, Object target) throws Throwable {
System . out. println ( "后置通知!返回值:" + returnValue + ", 方法名:" + method. getName ( ) + ", 参数表:" + Arrays . toString ( args) + ", 目标对象:" + target) ;
}
}
package com. bjsxt. advice ;
import org. aopalliance. intercept. MethodInterceptor ;
import org. aopalliance. intercept. MethodInvocation ;
public class MyAroundAdvice implements MethodInterceptor {
@Override
public Object invoke ( MethodInvocation invocation) throws Throwable {
Object returnValue = null ;
try {
System . out. println ( "环绕通知 - 前置" ) ;
returnValue = invocation. proceed ( ) ;
System . out. println ( "环绕通知 - 后置" ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
System . out. println ( "环绕通知 - 异常" ) ;
throw e;
}
return returnValue;
}
}
package com. bjsxt. advice ;
import org. springframework. aop. ThrowsAdvice ;
import java. lang. reflect. Method ;
public class MyThrowsAdvice implements ThrowsAdvice {
public void afterThrowing ( Method method, Object [ ] args, Object target, NullPointerException ex) {
System . out. println ( "异常通知 - 4个参数 - 空指针异常" ) ;
}
public void afterThrowing ( NullPointerException ex) {
System . out. println ( "异常通知 - 空指针异常" ) ;
}
public void afterThrowing ( RuntimeException ex) {
System . out. println ( "异常通知 - 运行时异常" ) ;
}
public void afterThrowing ( Method method, Object [ ] args, Object target, Exception ex) {
System . out. println ( "异常通知 - 4个参数 - 异常" ) ;
}
public void afterThrowing ( Exception ex) {
System . out. println ( "异常通知 - 异常" ) ;
}
}
package com. bjsxt. service. impl ;
import com. bjsxt. pojo. User ;
import com. bjsxt. service. UserService ;
import java. io. IOException ;
public class UserServiceImpl implements UserService {
@Override
public User login ( String username, String password) throws Exception {
System . out. println ( "登录方法运行: name = " + username + " , password = " + password) ;
if ( username == null ) {
throw new RuntimeException ( ) ;
}
return new User ( ) ;
}
@Override
public void sayHello ( ) {
System . out. println ( "你好,不要睡觉,不要玩手机!!! UserServiceImpl.sayHello() 方法运行!!!" ) ;
}
@Override
public String showInfo ( ) {
System . out. println ( "UserServiceImpl.showInfo()方法运行!! 大家好。我是堂堂,未婚,没车,没房,赚的多,花的少,。。。得早!!!" ) ;
return "大家好。我是堂堂,未婚,没车,没房,赚的多,花的少,。。。得早!!!" ;
}
@Override
public String sayHello ( String name) {
System . out. println ( "UserServiceImpl.sayHello(String)方法运行!! 你好," + name + "。UserServiceImpl.sayHello(String name) 方法运行 !!!" ) ;
return "你好," + name + "。UserServiceImpl.sayHello(String name) 方法运行 !!!" ;
}
@Override
public User getUserById ( Integer id) throws Exception {
User user = new User ( ) ;
user. setId ( id) ;
user. setName ( "姓名 - " + id) ;
System . out. println ( "UserServiceImpl.getUserById(Integer)方法运行,返回:" + user) ;
if ( id == 10 ) {
throw new NullPointerException ( ) ;
} else if ( id == 11 ) {
throw new RuntimeException ( ) ;
} else if ( id == 12 ) {
throw new Exception ( ) ;
} else if ( id == 13 ) {
throw new IndexOutOfBoundsException ( ) ;
} else if ( id == 14 ) {
throw new IOException ( ) ;
}
return user;
}
}
package com. bjsxt. test ;
import com. bjsxt. 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 ( "classpath:applicationContext.xml" )
public class TestAOP {
@Autowired
private UserService userService;
@Test
public void testAdvice ( ) throws Exception {
System . out. println ( userService. getClass ( ) . getName ( ) ) ;
userService. sayHello ( ) ;
System . out. println ( "============================================" ) ;
System . out. println ( "打印返回结果:" + userService. showInfo ( ) ) ;
System . out. println ( "============================================" ) ;
System . out. println ( "打印返回结果:" + userService. sayHello ( "张三" ) ) ;
System . out. println ( "============================================" ) ;
System . out. println ( "打印返回结果:" + userService. getUserById ( 1 ) ) ;
System . out. println ( "==================空指针异常==========================" ) ;
System . out. println ( "打印返回结果:" + userService. getUserById ( 10 ) ) ;
System . out. println ( "==================运行时异常==========================" ) ;
System . out. println ( "==================异常==========================" ) ;
System . out. println ( "==================下标越界异常==========================" ) ;
System . out. println ( "==================IO异常==========================" ) ;
}
}
【22】AspectJ
<?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"
default-autowire = " default" >
< bean id = " userService" class = " com.bjsxt.service.impl.UserServiceImpl" > </ bean>
< bean id = " firstAspect" class = " com.bjsxt.aspect.FirstAspectAdvice" > </ bean>
< bean id = " secondAspect" class = " com.bjsxt.aspect.SecondAspectAdvice" > </ bean>
< aop: config>
< aop: aspect ref = " secondAspect" >
< aop: pointcut id = " loginPointCut"
expression = " execution(com.bjsxt.pojo.User com.bjsxt.service.UserService.login(java.lang.String, java.lang.String) ) and args(username, password) " />
< aop: before method = " before" pointcut-ref = " loginPointCut" arg-names = " username, password" > </ aop: before>
< aop: after-returning method = " after" pointcut-ref = " loginPointCut" arg-names = " returnValue, username, password"
returning = " returnValue" > </ aop: after-returning>
< aop: around method = " around" pointcut-ref = " loginPointCut" arg-names = " point, username, password" > </ aop: around>
< aop: after-throwing method = " throwing" pointcut-ref = " loginPointCut" arg-names = " ex, username, password"
throwing = " ex" > </ aop: after-throwing>
</ aop: aspect>
< aop: aspect ref = " firstAspect" >
< aop: pointcut id = " all" expression = " execution( * com.bjsxt.service.*.* (..) )" />
< aop: before method = " before" pointcut-ref = " all" />
< aop: after-returning method = " afterReturning" pointcut-ref = " all" returning = " returnValue" />
< aop: around method = " around" pointcut-ref = " all" />
< aop: after-throwing method = " throwing" pointcut-ref = " all" throwing = " ex" />
</ aop: aspect>
</ aop: config>
</ beans>
package com. bjsxt. aspect ;
import org. aspectj. lang. ProceedingJoinPoint ;
public class FirstAspectAdvice {
public void before ( ) throws Throwable {
System . out. println ( "Aspect 前置通知" ) ;
}
public void afterReturning ( Object returnValue) throws Throwable {
System . out. println ( "Aspect 后置通知, 返回值是:" + returnValue) ;
}
public Object around ( ProceedingJoinPoint point) throws Throwable {
Object returnValue = null ;
try {
System . out. println ( "Aspect 环绕通知, 前置" ) ;
returnValue = point. proceed ( ) ;
System . out. println ( "Aspect 环绕通知, 后置" ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
System . out. println ( "Aspect 环绕通知, 异常" ) ;
throw e;
}
return returnValue;
}
public void throwing ( Exception ex) throws Throwable {
System . out. println ( "Aspect 异常通知" ) ;
}
}
package com. bjsxt. aspect ;
import org. aspectj. lang. ProceedingJoinPoint ;
public class SecondAspectAdvice {
public void before ( String username, String password) throws Throwable {
System . out. println ( "前置: username = " + username + " , password = " + password) ;
}
public void after ( Object returnValue, String username, String password) {
System . out. println ( "后置: username = " + username + " , password = " + password + ", 返回 = " + returnValue) ;
}
public Object around ( ProceedingJoinPoint point, String username, String password) throws Throwable {
System . out. println ( "环绕 - 前置: username = " + username + " , password = " + password) ;
Object returnValue = point. proceed ( new Object [ ] { username, password} ) ;
System . out. println ( "环绕 - 后置: username = " + username + " , password = " + password) ;
return returnValue;
}
public void throwing ( Exception ex, String username, String password) {
System . out. println ( "异常: username = " + username + " , password = " + password) ;
}
}
【23】String的不可变性
public class ImmutableStringInMethod {
public static void main ( String [ ] args) {
String originalStr = "Hello" ;
System . out. println ( "原始字符串: " + originalStr) ;
String modifiedStr = modifyString ( originalStr) ;
System . out. println ( "修改后的字符串: " + modifiedStr) ;
System . out. println ( "原始字符串未改变: " + originalStr) ;
}
public static String modifyString ( String str) {
str = str + ", World!" ;
return str;
}
}
【24】Schema-based和AspectJ区别
Schema-based 基于接口实现, AspectJ 基于配置实现的
Schame-based是运行时增强,AspectJ是编译时增强
切面比较多时,最好选择AspectJ方式
【25】注解方式实现AOP
package com. bjsxt. advice ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. annotation. * ;
import org. springframework. stereotype. Component ;
@Aspect
@Component
public class MyAdvice {
@Before ( "execution( void com.bjsxt.service.impl.UserServiceImpl.showInfo() )" )
public void showInfoBefore ( ) throws Throwable {
System . out. println ( "showInfo方法的前置通知" ) ;
}
@Before ( value = "execution( java.lang.String com.bjsxt.service.impl.UserServiceImpl.sayHello(java.lang.String) ) && args(name)" , argNames = "name" )
public void sayHelloBefore ( String name) throws Throwable {
System . out. println ( "sayHello方法前置通知, name = " + name) ;
}
@AfterReturning ( value = "execution( void com.bjsxt.service.impl.UserServiceImpl.showInfo() )" , returning = "returnValue" )
public void showInfoAfterReturning ( Object returnValue) {
System . out. println ( "showInfo方法的后置通知, 返回值 = " + returnValue) ;
}
@AfterReturning ( value = "execution( java.lang.String com.bjsxt.service.impl.UserServiceImpl.sayHello(java.lang.String) ) && args(name)" , returning = "returnValue" , argNames = "returnValue, name" )
public void sayHelloAfterReturning ( Object returnValue, String name) {
System . out. println ( "sayHello方法的后置通知, name = " + name + " ; 返回值 = " + returnValue) ;
}
@Around ( "execution( void com.bjsxt.service.impl.UserServiceImpl.showInfo() )" )
public Object showInfoAround ( ProceedingJoinPoint point) throws Throwable {
try {
System . out. println ( "showInfo方法环绕通知 - 前置" ) ;
Object returnValue = point. proceed ( ) ;
System . out. println ( "showInfo方法环绕通知 - 后置" ) ;
return returnValue;
} catch ( Exception e) {
System . out. println ( "showInfo方法环绕通知 - 异常" ) ;
throw e;
}
}
@Around ( value = "execution( java.lang.String com.bjsxt.service.impl.UserServiceImpl.sayHello(java.lang.String) ) && args(name)" , argNames = "point, name" )
public Object sayHelloAround ( ProceedingJoinPoint point, String name) throws Throwable {
try {
System . out. println ( "sayHello环绕 - 前置" ) ;
Object returnValue = point. proceed ( new Object [ ] { name} ) ;
System . out. println ( "sayHello环绕 - 后置" ) ;
return returnValue;
} catch ( Exception e) {
System . out. println ( "sayHello方法环绕 - 异常" ) ;
throw e;
}
}
@AfterThrowing ( value = "execution( void com.bjsxt.service.impl.UserServiceImpl.showInfo() )" , throwing = "e" )
public void showInfoAfterThrowing ( Exception e) {
System . out. println ( "showInfo方法的异常通知,异常类型是:" + e. getClass ( ) . getName ( ) ) ;
}
@AfterThrowing ( value = "execution( java.lang.String com.bjsxt.service.impl.UserServiceImpl.sayHello(java.lang.String) ) && args(name)" , throwing = "e" , argNames = "e, name" )
public void sayHelloAfterThrowing ( Exception e, String 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: 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"
default-autowire = " default" >
< context: component-scan base-package = " com.bjsxt" > </ context: component-scan>
< aop: aspectj-autoproxy proxy-target-class = " true" > </ aop: aspectj-autoproxy>
</ beans>
package com. bjsxt. service. impl ;
import com. bjsxt. service. UserService ;
import org. aspectj. lang. annotation. Pointcut ;
import org. springframework. stereotype. Service ;
@Service
public class UserServiceImpl implements UserService {
@Pointcut ( "execution( void com.bjsxt.service.impl.UserServiceImpl.showInfo() )" )
@Override
public void showInfo ( ) {
System . out. println ( "程序猿已经被规划为民工行列!!!" ) ;
}
@Override
@Pointcut ( "execution( java.lang.String com.bjsxt.service.impl.UserServiceImpl.sayHello(java.lang.String) ) && args(name) " )
public String sayHello ( String name) {
System . out. println ( "您好: " + name) ;
return "您好:" + name;
}
}
【26】Spring声明式事务配置
Spring框架提供了声明式事务管理机制。代码(Advice通知)配置都是已定义。只要按照框架给定的固定规则,编辑配置文件,就可以增加声明式事务。
要求:
1. 导入spring-tx.jar依赖
2. spring配置文件增加xml namespace
3. 按照规则配置事务管理机制。
3.1 配置spring提供的advice通知对象。是一个标签。这个通知对象,是基于DataSource中的Connection实现的事务管理。
3.2 配置spring提供的基于数据源的事务管理器
3.3 把配置好的事务管理通知,织入到目标位置。
<?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"
xmlns: tx= " http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd"
default-autowire = " default" >
< context: property-placeholder
location = " classpath:db/mysqlConfig.properties,classpath:config/owner.properties" > </ context: property-placeholder>
< bean id = " dataSource" class = " org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name = " driverClassName" value = " ${mysql.driver}" > </ property>
< property name = " url" value = " ${mysql.url}" > </ property>
< property name = " username" value = " ${mysql.username}" > </ property>
< property name = " password" value = " ${mysql.password}" > </ property>
</ bean>
< bean id = " transactionManager" class = " org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = " dataSource" ref = " dataSource" > </ property>
</ bean>
< aop: config>
< aop: pointcut id = " txPC" expression = " execution( * com.bjsxt.service.*.* (..) )" />
< aop: advisor advice-ref = " txAdvice" pointcut-ref = " txPC" />
</ aop: config>
< tx: advice id = " txAdvice" transaction-manager = " transactionManager" >
< tx: attributes>
< tx: method name = " addLoginLog" isolation = " DEFAULT" propagation = " REQUIRED" rollback-for = " java.lang.Exception"
no-rollback-for = " java.lang.Error" />
< tx: method name = " updateLoginLog" />
< tx: method name = " remove*" />
</ tx: attributes>
</ tx: advice>
</ beans>
【27】注解配置声明式事务
注解管理事务:
可以简化配置文件内容,提高开发效率。
要求:
1. 导入spring-tx.jar依赖
2. spring配置文件增加xml namespace tx
3. 只增加额外配置,bean对象,事务管理器
4. 在需要管理事务的方法上,增加注解。
< context: component-scan base-package = " com.bjsxt.service.impl" > </ context: component-scan>
< tx: annotation-driven> </ tx: annotation-driven>
< bean id = " transactionManager" class = " org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = " dataSource" ref = " dataSource" > </ property>
</ bean>
@Override
@Transactional ( transactionManager = "transactionManager" ,
propagation = Propagation . REQUIRED ,
isolation = Isolation . DEFAULT ,
rollbackFor = { java. lang. Exception. class } ,
noRollbackFor = { } ,
readOnly = false )
public int register ( Users users) {
System . out. println ( "代码版本是:" + version + " , 开发者 : " + owner + " , str1 = " + str1 + " , str2 = " + str2) ;
int rows = usersMapper. insertUsers ( users) ;
return rows;
}
【28】获取属性文件中值
@Value ( "${owner.version}" )
private String version;
@Value ( "${owner.name:也是默认值}" )
private String owner;
@Value ( "直接注入的字符串" )
private String str1;
@Value ( "${owner.str2:我是默认值}" )
private String str2;
# properties
owner.version=1.0
owner.name=kerwin_king
< context: property-placeholder
location = " classpath:db/mysqlConfig.properties,classpath:config/owner.properties" > </ context: property-placeholder>
< bean id = " dataSource" class = " org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name = " driverClassName" value = " ${mysql.driver}" > </ property>
< property name = " url" value = " ${mysql.url}" > </ property>
< property name = " username" value = " ${mysql.username}" > </ property>
< property name = " password" value = " ${mysql.password}" > </ property>
</ bean>
【30】Bean的生命周期
【31】代理模式
[1] 优点:
1. 如果需要为被调用的目标代码(服务端代码),增减功能,可以不修改原始代码。通过代理实现增减
2. 可以减少被调用的目标代码中的不必要逻辑。减少代码污染。
不必要的逻辑:
如: 业务代码(Service)中,如果需要记录日志数据。日志是业务代码么?
如果日志代码,写在service中,那么修改日志,不修改service业务逻辑,是否需要修改代码?是否需要重新编译?
[2] 种类:
1. 静态代理: 代理类型代码需要手工编写。
2. 动态代理: 代理类型代码不需要手工编写,自动生成。增减的功能,需要手工编写。
实现技术:
1. JDK : 基于接口的实现,提供动态代理。 被代理的类型,必须实现某接口,代理类型,实现同样的接口。 注意,必须是直接实现。
2. Cglib : 基于继承的实现,提供动态代理。被代理的类型,可以不实现接口,代理类型是被代理类型的子类型。需要导入三方jar包的。
[3] 静态代理实现:
必须手工定义一个静态代理类型。定义方式不限。只要能够最终调用被代理的方法即可。
[4] 动态代理实现: 不需要手工定义代理类型,只需要定义要增强的功能。 这个功能,需要实现接口。
JDK实现动态代理:基于接口
Cglib实现动态代理:基于父类型, 必须增加cglib依赖
[5] AOP 与 代理模式
Spring的AOP是面向切面编程,定义若干通知,织入到目标对象上。最终生成的就是代理对象。
SpringAOP的底层,默认使用JDK动态代理,生成AOP Proxy代理对象。
【32】代理模式 - 静态代理
package com. bjsxt. staticproxy ;
import com. bjsxt. serivice. UserService ;
public class MyProxy {
private UserService userService;
public void login ( ) {
try {
System . out. println ( "静态代理 - 前置" ) ;
userService. login ( ) ;
System . out. println ( "静态代理 - 后置" ) ;
} catch ( Exception e) {
System . out. println ( "静态代理 - 异常" ) ;
}
}
public MyProxy ( ) {
}
public MyProxy ( UserService userService) {
this . userService = userService;
}
public UserService getUserService ( ) {
return userService;
}
public void setUserService ( UserService userService) {
this . userService = userService;
}
}
package com. bjsxt. serivice. impl ;
import com. bjsxt. serivice. UserService ;
import java. util. Random ;
public class UserServiceImpl implements UserService {
@Override
public void login ( ) {
System . out. println ( "UserServiceImpl.login()方法运行。。。。" ) ;
Random random = new Random ( ) ;
if ( random. nextInt ( 10 ) % 3 == 0 ) {
throw new RuntimeException ( ) ;
}
}
}
package com. bjsxt. test ;
import com. bjsxt. serivice. UserService ;
import com. bjsxt. serivice. impl. UserServiceImpl ;
import com. bjsxt. staticproxy. MyProxy ;
import org. junit. Test ;
public class TestStaticProxy {
@Test
public void testStaticProxy ( ) {
UserService userService = new UserServiceImpl ( ) ;
MyProxy proxy = new MyProxy ( userService) ;
for ( int i = 0 ; i < 10 ; i++ ) {
proxy. login ( ) ;
}
}
}
【33】代理模式 - 动态代理(JDK)
package com. bjsxt. dynamicproxy ;
import com. bjsxt. serivice. UserService ;
import java. lang. reflect. InvocationHandler ;
import java. lang. reflect. Method ;
import java. lang. reflect. Proxy ;
import java. util. Arrays ;
public class MyJdkProxyHandler implements InvocationHandler {
private UserService target;
@Override
public Object invoke ( Object o, Method method, Object [ ] objects) throws Throwable {
try {
System . out. println ( "JDK动态代理 - 前置。" ) ;
Object returnValue = method. invoke ( target, objects) ;
System . out. println ( "目标方法返回值 = " + returnValue) ;
System . out. println ( "JDK动态代理 - 后置 。" ) ;
return returnValue;
} catch ( Exception e) {
e. printStackTrace ( ) ;
System . out. println ( "JDK动态代理 - 异常" ) ;
throw e;
}
}
public UserService getProxy ( ) {
return ( UserService ) Proxy . newProxyInstance ( this . getClass ( ) . getClassLoader ( ) , target. getClass ( ) . getInterfaces ( ) , this ) ;
}
public MyJdkProxyHandler ( ) {
}
public MyJdkProxyHandler ( UserService target) {
this . target = target;
}
public UserService getTarget ( ) {
return target;
}
public void setTarget ( UserService target) {
this . target = target;
}
}
package com. bjsxt. test ;
import com. bjsxt. dynamicproxy. MyJdkProxyHandler ;
import com. bjsxt. serivice. UserService ;
import com. bjsxt. serivice. impl. UserServiceImpl ;
import org. junit. Test ;
import java. util. Arrays ;
public class TestJDKProxy {
@Test
public void testJDKProxy ( ) {
UserService userService = new UserServiceImpl ( ) ;
MyJdkProxyHandler handler = new MyJdkProxyHandler ( userService) ;
UserService proxy = handler. getProxy ( ) ;
proxy. login ( ) ;
System . out. println ( proxy. getClass ( ) . getName ( ) ) ;
System . out. println ( Arrays . toString ( proxy. getClass ( ) . getInterfaces ( ) ) ) ;
System . out. println ( proxy. getClass ( ) . getSuperclass ( ) . getName ( ) ) ;
System . out. println ( proxy instanceof UserServiceImpl ) ;
}
}
package com. bjsxt. serivice. impl ;
import com. bjsxt. serivice. UserService ;
import java. util. Random ;
public class UserServiceImpl implements UserService {
@Override
public void login ( ) {
System . out. println ( "UserServiceImpl.login()方法运行。。。。" ) ;
Random random = new Random ( ) ;
if ( random. nextInt ( 10 ) % 3 == 0 ) {
throw new RuntimeException ( ) ;
}
}
}
【34】代理模式 - 动态代理(CGLIB)
< dependency>
< groupId> cglib</ groupId>
< artifactId> cglib</ artifactId>
< version> 3.3.0</ version>
</ dependency>
package com. bjsxt. dynamicproxy ;
import com. bjsxt. serivice. impl. UserServiceImpl ;
import net. sf. cglib. proxy. Enhancer ;
import net. sf. cglib. proxy. MethodInterceptor ;
import net. sf. cglib. proxy. MethodProxy ;
import java. lang. reflect. Method ;
public class MyCglibProxyHandler implements MethodInterceptor {
private UserServiceImpl target;
@Override
public Object intercept ( Object o, Method method, Object [ ] objects, MethodProxy methodProxy) throws Throwable {
try {
System . out. println ( "CGLIB动态代理前置" ) ;
Object returnValue = methodProxy. invokeSuper ( o, objects) ;
System . out. println ( "CGLIB动态代理后置" ) ;
return returnValue;
} catch ( Exception e) {
e. printStackTrace ( ) ;
System . out. println ( "CGLIB动态代理异常" ) ;
throw e;
}
}
public UserServiceImpl getProxy ( ) {
Enhancer enhancer = new Enhancer ( ) ;
enhancer. setSuperclass ( UserServiceImpl . class ) ;
enhancer. setCallback ( this ) ;
return ( UserServiceImpl ) enhancer. create ( ) ;
}
public MyCglibProxyHandler ( ) {
}
public MyCglibProxyHandler ( UserServiceImpl target) {
this . target = target;
}
public UserServiceImpl getTarget ( ) {
return target;
}
public void setTarget ( UserServiceImpl target) {
this . target = target;
}
}
package com. bjsxt. serivice. impl ;
import com. bjsxt. serivice. UserService ;
import java. util. Random ;
public class UserServiceImpl implements UserService {
@Override
public void login ( ) {
System . out. println ( "UserServiceImpl.login()方法运行。。。。" ) ;
Random random = new Random ( ) ;
if ( random. nextInt ( 10 ) % 3 == 0 ) {
throw new RuntimeException ( ) ;
}
}
}
package com. bjsxt. test ;
import com. bjsxt. dynamicproxy. MyCglibProxyHandler ;
import com. bjsxt. serivice. impl. UserServiceImpl ;
import org. junit. Test ;
import java. util. Arrays ;
public class TestCGLIBProxy {
@Test
public void test ( ) {
UserServiceImpl userService = new UserServiceImpl ( ) ;
MyCglibProxyHandler handler = new MyCglibProxyHandler ( userService) ;
UserServiceImpl proxy = handler. getProxy ( ) ;
proxy. login ( ) ;
System . out. println ( proxy. getClass ( ) . getName ( ) ) ;
System . out. println ( proxy. getClass ( ) . getSuperclass ( ) . getName ( ) ) ;
System . out. println ( Arrays . toString ( proxy. getClass ( ) . getInterfaces ( ) ) ) ;
}
}
【35】基于AspectJ实现登录日志
drop table if exists tb_login_log;
create table tb_login_log(
id int ( 11 ) primary key auto_increment ,
users_id int ( 11 ) comment '登录用户外键' ,
users_username varchar ( 32 ) comment '用户名' ,
remote_addr varchar ( 32 ) comment '客户端IP' ,
login_date datetime comment '登录时间' ,
login_result varchar ( 32 ) comment '登录结果: 成功 | 失败' ,
login_cause varchar ( 32 ) comment '登录失败原因: 用户名不存在 | 密码错误 | 代码异常等。如果登录成功,当前字段为null或空字符串'
) comment '登录日志表格' ;
package com. bjsxt. advice ;
import com. bjsxt. exception. LoginException ;
import com. bjsxt. exception. PasswordCheckFailException ;
import com. bjsxt. exception. PasswordNotEqException ;
import com. bjsxt. exception. UsernameNotFoundException ;
import com. bjsxt. mapper. LoginLogMapper ;
import com. bjsxt. pojo. LoginLog ;
import com. bjsxt. pojo. Users ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Component ;
import org. springframework. transaction. annotation. Transactional ;
import java. util. Date ;
@Component
public class LoginPostAdvice {
@Autowired
private LoginLogMapper loginLogMapper;
@Transactional
public void afterReturning ( Users returnValue, String username, String password, String remoteAddr) {
System . out. println ( "用户:" + returnValue. getName ( ) + ",在" + new Date ( ) + "时登录" ) ;
LoginLog loginLog = new LoginLog ( ) ;
loginLog. setUsersId ( returnValue. getId ( ) ) ;
loginLog. setUsersUsername ( returnValue. getUsername ( ) ) ;
loginLog. setLoginResult ( "成功" ) ;
loginLog. setLoginCause ( "" ) ;
loginLog. setRemoteAddr ( remoteAddr) ;
loginLog. setLoginDate ( new Date ( ) ) ;
System . out. println ( "新增日志前:" + loginLog) ;
loginLogMapper. insert ( loginLog) ;
System . out. println ( "新增日志后:" + loginLog) ;
}
@Transactional
public void afterThrowing ( LoginException e, String username, String password, String remoteAddr) {
LoginLog loginLog = new LoginLog ( ) ;
loginLog. setUsersUsername ( username) ;
loginLog. setLoginDate ( new Date ( ) ) ;
loginLog. setLoginResult ( "失败" ) ;
loginLog. setRemoteAddr ( remoteAddr) ;
if ( e instanceof UsernameNotFoundException ) {
System . out. println ( "用户名错误" ) ;
loginLog. setLoginCause ( "用户名不存在" ) ;
} else if ( e instanceof PasswordNotEqException ) {
System . out. println ( "密码错误" ) ;
loginLog. setLoginCause ( "密码错误" ) ;
} else if ( e instanceof PasswordCheckFailException ) {
System . out. println ( "密码长度错误,永远不运行,前置通知抛出异常,不会触发异常通知的运行。" ) ;
} else {
System . out. println ( "代码发生异常" ) ;
loginLog. setLoginCause ( "代码异常,类型是:" + e. getClass ( ) . getSimpleName ( ) ) ;
}
System . out. println ( "新增日志前:" + loginLog) ;
loginLogMapper. insert ( loginLog) ;
System . out. println ( "新增日志后:" + loginLog) ;
}
}
package com. bjsxt. servlet ;
import com. bjsxt. exception. LoginException ;
import com. bjsxt. exception. PasswordCheckFailException ;
import com. bjsxt. exception. PasswordNotEqException ;
import com. bjsxt. exception. UsernameNotFoundException ;
import com. bjsxt. pojo. Users ;
import com. bjsxt. service. UsersService ;
import org. springframework. web. context. support. WebApplicationContextUtils ;
import javax. servlet. ServletConfig ;
import javax. servlet. ServletException ;
import javax. servlet. annotation. WebServlet ;
import javax. servlet. http. HttpServlet ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. IOException ;
@WebServlet ( "/login" )
public class LoginServlet extends HttpServlet {
private UsersService usersService;
@Override
public void init ( ServletConfig config) throws ServletException {
super . init ( config) ;
usersService =
WebApplicationContextUtils . findWebApplicationContext ( config. getServletContext ( ) )
. getBean ( "usersService" , UsersService . class ) ;
}
@Override
protected void service ( HttpServletRequest req, HttpServletResponse resp) throws ServletException , IOException {
String username = req. getParameter ( "username" ) ;
String password = req. getParameter ( "password" ) ;
System . out. println ( "客户端:" + req. getRemoteAddr ( ) ) ;
try {
Users users = usersService. login ( username, password, req. getRemoteAddr ( ) ) ;
req. getSession ( ) . setAttribute ( "loginUser" , users) ;
resp. sendRedirect ( "/loginSuccess.jsp" ) ;
} catch ( UsernameNotFoundException ue) {
ue. printStackTrace ( ) ;
resp. sendRedirect ( "/loginFail.jsp" ) ;
} catch ( PasswordNotEqException pe) {
pe. printStackTrace ( ) ;
resp. sendRedirect ( "/loginFail.jsp" ) ;
} catch ( PasswordCheckFailException pce) {
pce. printStackTrace ( ) ;
resp. sendRedirect ( "/loginFail.jsp" ) ;
} catch ( LoginException le) {
le. printStackTrace ( ) ;
resp. sendRedirect ( "/error.jsp" ) ;
}
}
}
package com. bjsxt. service. impl ;
import com. bjsxt. exception. LoginException ;
import com. bjsxt. exception. PasswordNotEqException ;
import com. bjsxt. exception. UsernameNotFoundException ;
import com. bjsxt. mapper. UsersMapper ;
import com. bjsxt. pojo. Users ;
import com. bjsxt. service. UsersService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. stereotype. Service ;
import org. springframework. transaction. annotation. Isolation ;
import org. springframework. transaction. annotation. Propagation ;
import org. springframework. transaction. annotation. Transactional ;
@Service ( "usersService" )
public class UsersServiceImpl implements UsersService {
@Autowired
private UsersMapper usersMapper;
@Override
@Transactional
public Users login ( String username, String password, String remoteAddr) throws LoginException {
Users users = null ;
try {
users = usersMapper. selectByUsername ( username) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
throw new LoginException ( "用户登录异常-数据库访问错误" , e) ;
}
if ( users == null ) {
throw new UsernameNotFoundException ( "用户不存在" ) ;
}
if ( ! users. getPassword ( ) . equals ( password) ) {
throw new PasswordNotEqException ( "密码错误" ) ;
}
return users;
}
}
package com. bjsxt. mapper ;
import com. bjsxt. pojo. Users ;
public interface UsersMapper {
Users selectByUsername ( String username) ;
}
<?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 = " com.bjsxt.mapper.UsersMapper" >
< select id = " selectByUsername" resultType = " Users" >
select id, name, username, password from tb_users where username = #{username}
</ select>
</ mapper>
package com. bjsxt. mapper ;
import com. bjsxt. pojo. LoginLog ;
public interface LoginLogMapper {
int insert ( LoginLog loginLog) ;
}
<?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 = " com.bjsxt.mapper.LoginLogMapper" >
< insert id = " insert" useGeneratedKeys = " true" keyProperty = " id" >
insert into tb_login_log(id, users_id, login_result, login_cause, login_date, users_username, remote_addr)
values(default, #{usersId}, #{loginResult}, #{loginCause}, #{loginDate}, #{usersUsername}, #{remoteAddr})
</ insert>
</ mapper>
package com. bjsxt. exception ;
public class LoginException extends Exception {
public LoginException ( ) {
super ( ) ;
}
public LoginException ( String message) {
super ( message) ;
}
public LoginException ( String message, Throwable cause) {
super ( message, cause) ;
}
}
package com. bjsxt. exception ;
public class PasswordCheckFailException extends LoginException {
public PasswordCheckFailException ( ) {
super ( ) ;
}
public PasswordCheckFailException ( String message) {
super ( message) ;
}
public PasswordCheckFailException ( String message, Throwable cause) {
super ( message, cause) ;
}
}
package com. bjsxt. exception ;
public class PasswordNotEqException extends LoginException {
public PasswordNotEqException ( ) {
super ( ) ;
}
public PasswordNotEqException ( String message) {
super ( message) ;
}
public PasswordNotEqException ( String message, Throwable cause) {
super ( message, cause) ;
}
}
package com. bjsxt. exception ;
public class UsernameNotFoundException extends LoginException {
public UsernameNotFoundException ( ) {
super ( ) ;
}
public UsernameNotFoundException ( String message) {
super ( message) ;
}
public UsernameNotFoundException ( String message, Throwable cause) {
super ( message, cause) ;
}
}
package com. bjsxt. pojo ;
import java. io. Serializable ;
import java. util. Date ;
import java. util. Objects ;
public class LoginLog implements Serializable {
private Integer id;
private Integer usersId;
private String loginResult;
private String loginCause;
private String usersUsername;
private String remoteAddr;
private Date loginDate;
public LoginLog ( ) {
}
}