文章标题

来源:互联网 发布:域名怎么做跳转 编辑:程序博客网 时间:2024/06/06 06:49

《Spring4实战 第4版》2016年4月新出版的,之前的第三版看起来还是不错的,所以看到新版就直接买下来。

英文版源码地址:Spring in Action, Fourth Edition Covers Spring 4



1.IOC装配Bean

参考【spring实战4 2.2】,作者提倡无XML配置化

1.1接口只有一个现实类

可以自动装配

[java] view plain copy
print?
  1. public interface CompactDisc {  
  2.   
  3.     void play();  
  4. }  
public interface CompactDisc {    void play();}


[java] view plain copy
print?
  1. import org.springframework.stereotype.Component;  
  2.   
  3. @Component  
  4. public class SgtPeppers implements CompactDisc {  
  5.   
  6.     private String title = “Sgt. Pepper’s Lonely Hearts Club Band”;  
  7.     private String artist = “http://blog.csdn.net/unix21”;  
  8.   
  9.     public void play() {  
  10.         System.out.println(”【非常醒目SgtPeppers 】>>>>>>>>>>>>>>>>>Playing ” + title + “ by ” + artist);  
  11.     }  
  12.   
  13. }  
import org.springframework.stereotype.Component;@Componentpublic class SgtPeppers implements CompactDisc {    private String title = "Sgt. Pepper's Lonely Hearts Club Band";    private String artist = "http://blog.csdn.net/unix21";    public void play() {        System.out.println("【非常醒目SgtPeppers 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);    }}

[java] view plain copy
print?
  1. import org.springframework.context.annotation.ComponentScan;  
  2. import org.springframework.context.annotation.Configuration;  
  3.   
  4. @Configuration  
  5. @ComponentScan  
  6. public class CDPlayerConfig {   
  7. }  
import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScanpublic class CDPlayerConfig { }


单元测试

[java] view plain copy
print?
  1. import static org.junit.Assert.*;  
  2. import org.junit.Rule;  
  3. import org.junit.Test;  
  4. import org.junit.runner.RunWith;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.beans.factory.annotation.Qualifier;  
  7.   
  8. import org.springframework.test.context.ContextConfiguration;  
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  10.   
  11. @RunWith(SpringJUnit4ClassRunner.class)  
  12. @ContextConfiguration(classes = CDPlayerConfig.class)  
  13. public class CDPlayerTest {  
  14.     @Autowired  
  15.     private CompactDisc cd;  
  16.    
  17.     @Test  
  18.     public void play() {  
  19.         cd.play();  
  20.     }  
  21. }  
import static org.junit.Assert.*;import org.junit.Rule;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = CDPlayerConfig.class)public class CDPlayerTest {    @Autowired    private CompactDisc cd;    @Test    public void play() {        cd.play();    }}




1.2 接口有多个实现类

【参考 Spring实战4 3.3】
故意再写一个实现类

[java] view plain copy
print?
  1. import org.springframework.stereotype.Component;  
  2.   
  3. @Component  
  4. public class SgtPeppersNew implements CompactDisc {  
  5.   
  6.     private String title = “Sgt. Pepper’s Lonely Hearts Club Band”;  
  7.     private String artist = “http://blog.csdn.net/unix21”;  
  8.   
  9.     public void play() {  
  10.         System.out.println(”【非常醒目 SgtPeppersNew】>>>>>>>>>>>>>>>>>Playing ” + title + “ by ” + artist);  
  11.     }  
  12.   
  13. }  
import org.springframework.stereotype.Component;@Componentpublic class SgtPeppersNew implements CompactDisc {    private String title = "Sgt. Pepper's Lonely Hearts Club Band";    private String artist = "http://blog.csdn.net/unix21";    public void play() {        System.out.println("【非常醒目 SgtPeppersNew】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);    }}

如果这个时候运行肯定会报错NoUniqueBeanDefinitionException: No qualifying bean of type


解决方法有两种

第一种 在实现类上 标识首选的bean,使用@Primary

[java] view plain copy
print?
  1. import org.springframework.context.annotation.Primary;  
  2. import org.springframework.stereotype.Component;  
  3.   
  4. @Component  
  5. @Primary  
  6. public class SgtPeppers implements CompactDisc {  
  7.   
  8.     private String title = “Sgt. Pepper’s Lonely Hearts Club Band”;  
  9.     private String artist = “http://blog.csdn.net/unix21”;  
  10.   
  11.     public void play() {  
  12.         System.out.println(”【非常醒目SgtPeppers 】>>>>>>>>>>>>>>>>>Playing ” + title + “ by ” + artist);  
  13.     }  
  14.   
  15. }  
import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Component;@Component@Primarypublic class SgtPeppers implements CompactDisc {    private String title = "Sgt. Pepper's Lonely Hearts Club Band";    private String artist = "http://blog.csdn.net/unix21";    public void play() {        System.out.println("【非常醒目SgtPeppers 】>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);    }}


但是这种方法不方便精确定义。


第二种  使用@Qualifier注解

[java] view plain copy
print?
  1. import static org.junit.Assert.*;  
  2. import org.junit.Rule;  
  3. import org.junit.Test;  
  4. import org.junit.runner.RunWith;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.beans.factory.annotation.Qualifier;  
  7.   
  8. import org.springframework.test.context.ContextConfiguration;  
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  10.   
  11. @RunWith(SpringJUnit4ClassRunner.class)  
  12. @ContextConfiguration(classes = CDPlayerConfig.class)  
  13. public class CDPlayerTest {  
  14.     @Autowired  
  15.     @Qualifier(“sgtPeppersNew”)   
  16.     private CompactDisc cd;  
  17.    
  18.     @Test  
  19.     public void play() {  
  20.         cd.play();  
  21.     }  
  22. }  
import static org.junit.Assert.*;import org.junit.Rule;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = CDPlayerConfig.class)public class CDPlayerTest {    @Autowired    @Qualifier("sgtPeppersNew")     private CompactDisc cd;    @Test    public void play() {        cd.play();    }}

需要注意的是bean id的首字母是类名小写。

spring @Qualifier注解


1.3 为组件扫描的bean命名

【参考 Spring实战4  2.2.2】

[java] view plain copy
print?
  1. import org.springframework.stereotype.Component;  
  2.   
  3. @Component(“spn”)  
  4. public class SgtPeppersNew implements CompactDisc {  
import org.springframework.stereotype.Component;@Component("spn")public class SgtPeppersNew implements CompactDisc {

[java] view plain copy
print?
  1. @Autowired  
  2.     @Qualifier(“spn”)   
  3.     private CompactDisc cd;  
@Autowired    @Qualifier("spn")     private CompactDisc cd;

也可以使用@Named效果是一样的,这是java依赖注入规范

[java] view plain copy
print?
  1. import javax.inject.Named;  
  2.   
  3. @Named(“spn”)  
  4. public class SgtPeppersNew implements CompactDisc {  
import javax.inject.Named;@Named("spn")public class SgtPeppersNew implements CompactDisc {

1.4 设定组件扫描的指定包

【参考 Spring实战4  2.2.3】

如果@ComponentScan默认不设置只扫描配置类所在的包作为基础包。

[java] view plain copy
print?
  1. @Configuration  
  2. @ComponentScan(“blog.csdn.net.unix21”)  
  3. public class CDPlayerConfigTest {  
@Configuration@ComponentScan("blog.csdn.net.unix21")public class CDPlayerConfigTest {
设置@ComponentScan的value属性就可以指明包名称。


如果想更清晰的表明设置的是基础包
@ComponentScan(basePackages=”指定包”)


指定多个

@ComponentScan(basePackages={“指定包1”,”指定包2”})


也可以将其指定为包中所包含的类或者接口

@ComponentScan(basePackages={“XXX.class”,”XX.class”})


1.5 自动装配

【参考 Spring实战4  2.2.4】

声明自动装配需要@Autowired注解


1.5.1 在构造方法上使用自动装配

[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = CDPlayerConfigTest.class)  
  3. public class CDPlayerFunTest {  
  4.   
  5.     private CompactDisc cd;  
  6.   
  7.     @Autowired  
  8.     @Qualifier(“spn”)  
  9.     public void CDPlayer(CompactDisc cd) {  
  10.         this.cd = cd;  
  11.     }  
  12.   
  13.     @Test  
  14.     public void play() {  
  15.         cd.play();  
  16.         System.out.println(”【占位符】CDPlayerFunTest”);  
  17.     }  
  18. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = CDPlayerConfigTest.class)public class CDPlayerFunTest {    private CompactDisc cd;    @Autowired    @Qualifier("spn")    public void CDPlayer(CompactDisc cd) {        this.cd = cd;    }    @Test    public void play() {        cd.play();        System.out.println("【占位符】CDPlayerFunTest");    }}


另一种写法

[java] view plain copy
print?
  1. @Component  
  2. public class CDPlayer implements MediaPlayer {  
  3.   private CompactDisc cd;  
  4.   
  5.   @Autowired  
  6.   public CDPlayer(@Qualifier(“spn”)CompactDisc cd) {  
  7.     this.cd = cd;  
  8.   }  
  9.   
  10.   public void play() {  
  11.     cd.play();  
  12.   }  
  13.   
  14. }  
@Componentpublic class CDPlayer implements MediaPlayer {  private CompactDisc cd;  @Autowired  public CDPlayer(@Qualifier("spn")CompactDisc cd) {    this.cd = cd;  }  public void play() {    cd.play();  }}


1.5.2 在属性Setter方法上使用自动装配

[java] view plain copy
print?
  1. @Component  
  2. public class CDPlayer implements MediaPlayer {  
  3.   private CompactDisc cd;  
  4.     
  5.   @Autowired  
  6.   @Qualifier(“spn”)  
  7.   public void setCompactDisc(CompactDisc cd) {  
  8.     this.cd = cd;  
  9.   }  
  10.   
  11.   public void play() {  
  12.     cd.play();  
  13.   }  
  14. }  
@Componentpublic class CDPlayer implements MediaPlayer {  private CompactDisc cd;  @Autowired  @Qualifier("spn")  public void setCompactDisc(CompactDisc cd) {    this.cd = cd;  }  public void play() {    cd.play();  }}

避免异常声明  @Autowired(required = false),如果没有匹配的bean,Spring会让这个bean处于未装配转态,但是需要谨慎对待这个设置,代码需要做null检查。

@Autowired是Spring特有的注解,可以替换为@Inject,@Inject来源自Jave依赖注入规范。


1.6 创建自定义的限定符

【参考 Spring实战4  3.3.2】

[java] view plain copy
print?
  1. @Component  
  2. @Qualifier(“cold”)  
  3. public class IceCream implements CompactDisc {  
  4.   
  5.     private String title = “Sgt. Pepper’s Lonely Hearts Club Band”;  
  6.     private String artist = “The Beatles”;  
  7.   
  8.     public void play() {  
  9.         System.out.println(”【非常醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing ” + title + “ by ” + artist);  
  10.     }  
  11. }  
@Component@Qualifier("cold")public class IceCream implements CompactDisc {    private String title = "Sgt. Pepper's Lonely Hearts Club Band";    private String artist = "The Beatles";    public void play() {        System.out.println("【非常醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);    }}


测试用例
[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes=CDPlayerConfigTest.class)  
  3. public class CDPlayerLogTest {  
  4.   
  5.   @Autowired  
  6.   private MediaPlayer player;  
  7.     
  8.   @Autowired  
  9.   @Qualifier(“sp”)  
  10.   private CompactDisc cd;  
  11.     
  12.   @Autowired  
  13.   @Qualifier(“cold”)  
  14.   private CompactDisc cd2;  
  15.     
  16.   @Test  
  17.   public void cdShouldNotBeNull() {  
  18.     assertNotNull(cd);  
  19.   }  
  20.   
  21.   @Test  
  22.   public void play() {  
  23.     player.play();  
  24.     cd.play();  
  25.     cd2.play();  
  26.   }  
  27. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=CDPlayerConfigTest.class)public class CDPlayerLogTest {  @Autowired  private MediaPlayer player;  @Autowired  @Qualifier("sp")  private CompactDisc cd;  @Autowired  @Qualifier("cold")  private CompactDisc cd2;  @Test  public void cdShouldNotBeNull() {    assertNotNull(cd);  }  @Test  public void play() {    player.play();    cd.play();    cd2.play();  }}


好处:这样做的好处限定符不耦合类名,所以可以随意重构类名。

问题:重复的限定符出现在多个类上这是不允许的,因为Java不允许同一个条目上重复出现相同类型的多个注解


1.7 使用自定义限定符注解

针对上述问题可以创建自定义的限定符注解。

[java] view plain copy
print?
  1. @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到    
  2. @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法    
  3. @Qualifier  
  4. public @interface Cold {}  
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法  @Qualifierpublic @interface Cold {}

[java] view plain copy
print?
  1. @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到    
  2. @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法    
  3. @Qualifier  
  4. public @interface Creamy {}  
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法  @Qualifierpublic @interface Creamy {}

[java] view plain copy
print?
  1. @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到    
  2. @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法    
  3. @Qualifier  
  4. public @interface Fruity {}  
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})//定义注解的作用目标**作用范围字段、枚举的常量/方法  @Qualifierpublic @interface Fruity {}

[java] view plain copy
print?
  1. @Component  
  2. @Cold  
  3. @Creamy  
  4. public class IceCream implements CompactDisc {  
  5.   
  6.     private String title = “Spring 实现 第4版 读书笔记”;  
  7.     private String artist = “http://blog.csdn.net/unix21”;  
  8.   
  9.     public void play() {  
  10.         System.out.println(”【非常醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing ” + title + “ by ” + artist);  
  11.     }  
  12. }  
@Component@Cold@Creamypublic class IceCream implements CompactDisc {    private String title = "Spring 实现 第4版 读书笔记";    private String artist = "http://blog.csdn.net/unix21";    public void play() {        System.out.println("【非常醒目 IceCream】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);    }}

[java] view plain copy
print?
  1. @Component  
  2. @Cold  
  3. @Fruity  
  4. public class Popsicle implements CompactDisc {  
  5.   
  6.     private String title = “Spring 实现 第4版 读书笔记”;  
  7.     private String artist = “http://blog.csdn.net/unix21”;  
  8.   
  9.     public void play() {  
  10.         System.out.println(”【非常醒目 Popsicle】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing ” + title + “ by ” + artist);  
  11.     }  
  12. }  
@Component@Cold@Fruitypublic class Popsicle implements CompactDisc {    private String title = "Spring 实现 第4版 读书笔记";    private String artist = "http://blog.csdn.net/unix21";    public void play() {        System.out.println("【非常醒目 Popsicle】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Playing " + title + " by " + artist);    }}

[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = CDPlayerConfigTest.class)  
  3. public class CDPlayerLogTest {  
  4.   
  5.     @Autowired  
  6.     private MediaPlayer player;  
  7.   
  8.     @Autowired  
  9.     @Qualifier(“sp”)  
  10.     private CompactDisc cd;  
  11.   
  12.     @Autowired  
  13.     @Cold  
  14.     @Creamy  
  15.     private CompactDisc cd2;  
  16.   
  17.     @Autowired  
  18.     @Cold  
  19.     @Fruity  
  20.     private CompactDisc cd3;  
  21.   
  22.     @Test  
  23.     public void cdShouldNotBeNull() {  
  24.         assertNotNull(cd);  
  25.     }  
  26.   
  27.     @Test  
  28.     public void play() {  
  29.         player.play();  
  30.         cd.play();  
  31.         cd2.play();  
  32.         cd3.play();  
  33.     }  
  34. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = CDPlayerConfigTest.class)public class CDPlayerLogTest {    @Autowired    private MediaPlayer player;    @Autowired    @Qualifier("sp")    private CompactDisc cd;    @Autowired    @Cold    @Creamy    private CompactDisc cd2;    @Autowired    @Cold    @Fruity    private CompactDisc cd3;    @Test    public void cdShouldNotBeNull() {        assertNotNull(cd);    }    @Test    public void play() {        player.play();        cd.play();        cd2.play();        cd3.play();    }}


1.8 bean的作用域

Spring定义了多重作用域,singleton单例,prototype原型等

参考:spring中scope作用域

singleton单例:整个应用中,只创建bean的一个实例,默认Spring上下文中所有的bean都是单例。

prototype原型:每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。

[java] view plain copy
print?
  1. @Component  
  2. public class Add implements AddI {  
  3.     public  int a=0;  
  4.      
  5.     public  void Add() {  
  6.         a++;  
  7.     }  
  8.       
  9.     public  void getA() {  
  10.         System.out.println(”【非常醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= ” +a+“”);  
  11.     }  
  12. }  
@Componentpublic class Add implements AddI {    public  int a=0;    public  void Add() {        a++;    }    public  void getA() {        System.out.println("【非常醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= " +a+"");    }}

[java] view plain copy
print?
  1. public interface AddI {  
  2. void Add();  
  3.     void getA();  
  4. }  
public interface AddI {void Add();    void getA();}

[java] view plain copy
print?
  1. @Component  
  2. public class CDPlayer implements MediaPlayer {  
  3.   
  4.     @Autowired  
  5.     @Qualifier(“sp”)  
  6.     private CompactDisc cd;  
  7.       
  8.     @Autowired  
  9.     private AddI a;  
  10.   
  11.     public void play() {  
  12.         System.out.println(”【非常醒目 CDPlayer】>>>”);  
  13.         cd.play();  
  14.         a.Add();  
  15.         a.getA();  
  16.         a.Add();  
  17.         a.getA();  
  18.         System.out.println(”【非常醒目 CDPlayer】<<<”);  
  19.     }  
  20. }  
@Componentpublic class CDPlayer implements MediaPlayer {    @Autowired    @Qualifier("sp")    private CompactDisc cd;    @Autowired    private AddI a;    public void play() {        System.out.println("【非常醒目 CDPlayer】>>>");        cd.play();        a.Add();        a.getA();        a.Add();        a.getA();        System.out.println("【非常醒目 CDPlayer】<<<");    }}


测试用例
[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = CDPlayerConfigTest.class)  
  3. public class CDPlayerLogTest {  
  4.   
  5.     @Autowired  
  6.     private MediaPlayer player;  
  7.   
  8.     @Autowired  
  9.     @Qualifier(“sp”)  
  10.     private CompactDisc cd;  
  11.   
  12.     @Autowired  
  13.     @Cold  
  14.     @Creamy  
  15.     private CompactDisc cd2;  
  16.   
  17.     @Autowired  
  18.     @Cold  
  19.     @Fruity  
  20.     private CompactDisc cd3;  
  21.   
  22.     @Test  
  23.     public void cdShouldNotBeNull() {  
  24.         assertNotNull(cd);  
  25.     }  
  26.   
  27.     @Autowired  
  28.     private AddI a;  
  29.       
  30.     @Test  
  31.     public void play() {  
  32.         player.play();  
  33.         cd.play();  
  34.         cd2.play();  
  35.         cd3.play();  
  36.         a.getA();  
  37.     }  
  38. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = CDPlayerConfigTest.class)public class CDPlayerLogTest {    @Autowired    private MediaPlayer player;    @Autowired    @Qualifier("sp")    private CompactDisc cd;    @Autowired    @Cold    @Creamy    private CompactDisc cd2;    @Autowired    @Cold    @Fruity    private CompactDisc cd3;    @Test    public void cdShouldNotBeNull() {        assertNotNull(cd);    }    @Autowired    private AddI a;    @Test    public void play() {        player.play();        cd.play();        cd2.play();        cd3.play();        a.getA();    }}


再写一个多线程

[java] view plain copy
print?
  1. public class ClientThread extends Thread {  
  2.   
  3.     @Autowired  
  4.     private AddI a;  
  5.   
  6.     @Autowired  
  7.     public ClientThread(AddI a) {  
  8.         this.a = a;  
  9.     }  
  10.   
  11.     public void run() {  
  12.         a.Add();  
  13.         a.getA();  
  14.     }  
  15. }  
public class ClientThread extends Thread {    @Autowired    private AddI a;    @Autowired    public ClientThread(AddI a) {        this.a = a;    }    public void run() {        a.Add();        a.getA();    }}

调用多线程

[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = CDPlayerConfigTest.class)  
  3. public class SpringScopeTest {  
  4.   
  5.     @Autowired  
  6.     private AddI a;  
  7.   
  8.     @Test  
  9.     public void Scope() {  
  10.         for (int i = 0; i < 10; i++) {  
  11.             ClientThread t = new ClientThread(a);  
  12.             t.start();  
  13.         }  
  14.     }  
  15. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = CDPlayerConfigTest.class)public class SpringScopeTest {    @Autowired    private AddI a;    @Test    public void Scope() {        for (int i = 0; i < 10; i++) {            ClientThread t = new ClientThread(a);            t.start();        }    }}


改为SCOPE_PROTOTYPE

[java] view plain copy
print?
  1. @Component  
  2. @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  
  3. //@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)  
  4. public class Add implements AddI {  
  5.     public  int a=0;  
  6.      
  7.     public  void Add() {  
  8.         a++;  
  9.     }  
  10.       
  11.     public  void getA() {  
  12.         System.out.println(”【非常醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= ” +a+“”);  
  13.     }  
  14. }  
@Component@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)//@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)public class Add implements AddI {    public  int a=0;    public  void Add() {        a++;    }    public  void getA() {        System.out.println("【非常醒目 Add】>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>a= " +a+"");    }}



看到差异了吧。


补充说明:@Repository、@Service、@Controller 和 @Component将类标识为Bean,都是一样的,用在不同的地方而已。


2.AOP切面编程

定义接口

[java] view plain copy
print?
  1. public interface PerformanceI {  
  2.     public void perform();  
  3. }  
public interface PerformanceI {    public void perform();}

实现类

[java] view plain copy
print?
  1. import org.springframework.stereotype.Component;  
  2.   
  3. @Component  
  4. public class Performance implements PerformanceI{  
  5.     public void perform(){  
  6.     System.out.println(”【非常醒目  Performance perform 调用中】 By http://blog.csdn.net/unix21”);     
  7.     }  
  8. }  
import org.springframework.stereotype.Component;@Componentpublic class Performance implements PerformanceI{    public void perform(){    System.out.println("【非常醒目  Performance perform 调用中】 By http://blog.csdn.net/unix21");       }}

定义切面

[java] view plain copy
print?
  1. import org.aspectj.lang.annotation.After;  
  2. import org.aspectj.lang.annotation.AfterThrowing;  
  3. import org.aspectj.lang.annotation.Aspect;  
  4. import org.aspectj.lang.annotation.Before;  
  5.   
  6. @Aspect  
  7. public class MyAspect {  
  8.     @Before(“execution(* com.demo.PerformanceI.perform(..))”)  
  9.     public void before(){  
  10.     System.out.println(”【非常醒目 [方法调用前] 】”);  
  11.     }  
  12.       
  13.     @After(“execution(* com.demo.PerformanceI.perform(..))”)  
  14.     public void after(){  
  15.     System.out.println(”【非常醒目 [方法调用后] 】”);  
  16.     }  
  17.       
  18.     @AfterThrowing(“execution(* com.demo.PerformanceI.perform(..))”)  
  19.     public void afterThrowing(){  
  20.     System.out.println(”【非常醒目 [方法异常后] 】”);  
  21.     }  
  22. }  
import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class MyAspect {    @Before("execution(* com.demo.PerformanceI.perform(..))")    public void before(){    System.out.println("【非常醒目 [方法调用前] 】");    }    @After("execution(* com.demo.PerformanceI.perform(..))")    public void after(){    System.out.println("【非常醒目 [方法调用后] 】");    }    @AfterThrowing("execution(* com.demo.PerformanceI.perform(..))")    public void afterThrowing(){    System.out.println("【非常醒目 [方法异常后] 】");    }}

配置文件

[java] view plain copy
print?
  1. import com.demo.*;  
  2. import org.springframework.context.annotation.Bean;  
  3. import org.springframework.context.annotation.ComponentScan;  
  4. import org.springframework.context.annotation.Configuration;  
  5. import org.springframework.context.annotation.EnableAspectJAutoProxy;  
  6.   
  7. @Configuration  
  8. @EnableAspectJAutoProxy  
  9. @ComponentScan(“com.demo”)  
  10. public class AppConfig {  
  11.     @Bean  
  12.     public MyAspect myAspect() {  
  13.         return new MyAspect();  
  14.     }  
  15.      
  16. }  
import com.demo.*;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration@EnableAspectJAutoProxy@ComponentScan("com.demo")public class AppConfig {    @Bean    public MyAspect myAspect() {        return new MyAspect();    }}


测试用例

[java] view plain copy
print?
  1. import org.junit.Test;  
  2. import org.junit.runner.RunWith;  
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.test.context.ContextConfiguration;  
  5. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  6.   
  7. @RunWith(SpringJUnit4ClassRunner.class)  
  8. @ContextConfiguration(classes = AppConfig.class)  
  9. public class MyTest {  
  10.   
  11.     @Autowired  
  12.     private PerformanceI p1;  
  13.       
  14.     @Test  
  15.     public void play() {  
  16.         p1.perform();  
  17.     }  
  18. }  
import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = AppConfig.class)public class MyTest {    @Autowired    private PerformanceI p1;    @Test    public void play() {        p1.perform();    }}


运行:


实现了方法调用前后的AOP效果。

这个Spring官方参考做的不错:http://docs.spring.io/spring/docs/4.2.5.RELEASE/javadoc-api/

这里选不同的版本:http://docs.spring.io/spring/docs/



3.Spring MVC

DispatcherServlet是Spring MVC的核心,每当应用接受一个HTTP请求,由DispatcherServlet负责将请求分发给应用的其他组件。
在旧版本中,DispatcherServlet之类的servlet一般在web.xml文件中配置;但是Spring 3.1引入了注解就无需再使用web.xml文件。

[java] view plain copy
print?
  1. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;  
  2.   
  3. public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {  
  4.   
  5.     @Override  
  6.     protected Class<?>[] getRootConfigClasses() {  
  7.         return new Class<?>[]{RootConfig.class};  
  8.     }  
  9.   
  10.     @Override  
  11.     protected Class<?>[] getServletConfigClasses() {  
  12.         return new Class<?>[]{WebConfig.class};  
  13.     }  
  14.   
  15.     @Override  
  16.     protected String[] getServletMappings() {  
  17.         return new String[]{“/”};  
  18.     }  
  19.   
  20. }  
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {    @Override    protected Class<?>[] getRootConfigClasses() {        return new Class<?>[]{RootConfig.class};    }    @Override    protected Class<?>[] getServletConfigClasses() {        return new Class<?>[]{WebConfig.class};    }    @Override    protected String[] getServletMappings() {        return new String[]{"/"};    }}

AbstractAnnotationConfigDispatcherServletInitializer这个类负责配置DispatcherServlet、初始化Spring MVC容器和Spring容器。


正如可以通过多种方式配置DispatcherServlet一样,也可以通过多种方式启动Spring MVC特性。原来我们一般在xml文件中使用<mvc:annotation-driven>元素启动注解驱动的Spring MVC特性。这里我们使用JavaConfig配置,最简单的Spring MVC配置类代码如下:

[java] view plain copy
print?
  1. import org.springframework.context.annotation.Bean;  
  2. import org.springframework.context.annotation.ComponentScan;  
  3. import org.springframework.context.annotation.Configuration;  
  4. import org.springframework.web.servlet.ViewResolver;  
  5. import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;  
  6. import org.springframework.web.servlet.config.annotation.EnableWebMvc;  
  7. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  
  8. import org.springframework.web.servlet.view.InternalResourceViewResolver;  
  9.   
  10. @Configuration  
  11. @EnableWebMvc  
  12. @ComponentScan(“com.xxx.controller”)  
  13. public class WebConfig extends WebMvcConfigurerAdapter{  
  14.     @Bean  
  15.     public ViewResolver viewResolver() { //配置JSP视图解析器  
  16.         InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
  17.         resolver.setPrefix(”/WEB-INF/views/”);  
  18.         resolver.setSuffix(”.jsp”);  
  19.         //可以在JSP页面中通过${}访问beans  
  20.         resolver.setExposeContextBeansAsAttributes(true);  
  21.         return resolver;  
  22.     }  
  23.   
  24.     @Override  
  25.     public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {  
  26.         configurer.enable(); //配置静态文件处理  
  27.     }  
  28. }  
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.ViewResolver;import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;import org.springframework.web.servlet.config.annotation.EnableWebMvc;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import org.springframework.web.servlet.view.InternalResourceViewResolver;@Configuration@EnableWebMvc@ComponentScan("com.xxx.controller")public class WebConfig extends WebMvcConfigurerAdapter{    @Bean    public ViewResolver viewResolver() { //配置JSP视图解析器        InternalResourceViewResolver resolver = new InternalResourceViewResolver();        resolver.setPrefix("/WEB-INF/views/");        resolver.setSuffix(".jsp");        //可以在JSP页面中通过${}访问beans        resolver.setExposeContextBeansAsAttributes(true);        return resolver;    }    @Override    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {        configurer.enable(); //配置静态文件处理    }}
@Configuration表示这是Java配置类;@EnableWebMvc注解用于启动Spring MVC特性。

通过@ComponentScan注解指定bean的自动发现机制作用的范围,被@Controller等注解修饰的web的bean将被发现并加载到spring mvc应用容器,这样就不需要在配置类中显式定义任何控制器bean了。

通过@Bean注解添加一个ViewResolverbean,具体来说是InternalResourceViewResolver。


RootConfig的配置就非常简单了,唯一需要注意的是,它在设置扫描机制的时候,将之前WebConfig设置过的那个包排除了;也就是说,这两个扫描机制作用的范围正交。RootConfig的代码如下:

[java] view plain copy
print?
  1. import org.springframework.context.annotation.ComponentScan;  
  2. import org.springframework.context.annotation.Configuration;  
  3. import org.springframework.context.annotation.FilterType;  
  4. import org.springframework.web.servlet.config.annotation.EnableWebMvc;  
  5.   
  6. @Configuration  
  7. @ComponentScan(basePackages = {“com.xxx.*”},  
  8.         excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)})  
  9. public class RootConfig {  
  10. }  
import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.FilterType;import org.springframework.web.servlet.config.annotation.EnableWebMvc;@Configuration@ComponentScan(basePackages = {"com.xxx.*"},        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)})public class RootConfig {}


写一个控制器,定义之前的IOC对象PerformanceI

[java] view plain copy
print?
  1. @Controller  
  2. public class HomeController {  
  3.     @Autowired  
  4.     private PerformanceI p1;  
  5.       
  6.     @RequestMapping(value = “/home”, method = RequestMethod.GET)  
  7.     public String home() {  
  8.         p1.perform();  
  9.         return “home”;  
  10.     }  
  11. }  
@Controllerpublic class HomeController {    @Autowired    private PerformanceI p1;    @RequestMapping(value = "/home", method = RequestMethod.GET)    public String home() {        p1.perform();        return "home";    }}


在WEB-INF/views下新增模板文件home.jsp
[html] view plain copy
print?
  1. <%@page contentType=“text/html” pageEncoding=“UTF-8”%>  
  2. <!DOCTYPE html>  
  3. <html>  
  4.     <head>  
  5.         <meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”>  
  6.         <title>JSP Page</title>  
  7.     </head>  
  8.     <body>  
  9.         <h1>Spring4 & Sping MVC4 </h1><p>demo by http://blog.csdn.net/unix21</p>  
  10.     </body>  
  11. </html>  
<%@page contentType="text/html" pageEncoding="UTF-8"%><!DOCTYPE html><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">        <title>JSP Page</title>    </head>    <body>        <h1>Spring4 & Sping MVC4 </h1><p>demo by http://blog.csdn.net/unix21</p>    </body></html>




下面这个是【第5章】的翻译 https://segmentfault.com/a/1190000004343063?_ea=575820


默认首页

我们希望用户访问域名直接到默认首页,那么需要删除网站web目录下的index.html。

tomcat会自动默认去寻找在webroot目录下面的index文件,如果要使用自定义方法,则要保证webroot下面没有index相关的文件。


自己写一个index

[java] view plain copy
print?
  1. @RequestMapping(value = “/”, method = RequestMethod.GET)  
  2.     public String index() {  
  3.         return “index”;  
  4.     }  
@RequestMapping(value = "/", method = RequestMethod.GET)    public String index() {        return "index";    }

再定义一个index.jsp即可

具体请参考:Spring MVC 下设置默认访问页面的3种方式


映射多个地址

[java] view plain copy
print?
  1. @RequestMapping(value = {“”“/”,“index”}, method = RequestMethod.GET)  
  2.    public String index() {  
  3.        return “index”;  
  4.    }  
 @RequestMapping(value = {"", "/","index"}, method = RequestMethod.GET)    public String index() {        return "index";    }
或者
[java] view plain copy
print?
  1. @RequestMapping({“”“/”,“index”})  
  2.    public String index() {  
  3.        return “index”;  
  4.    }  
 @RequestMapping({"", "/","index"})    public String index() {        return "index";    }


输出json

形式一

[java] view plain copy
print?
  1. @ResponseBody  
  2.     @RequestMapping(value = “/list”, method = RequestMethod.GET,produces = “text/json;charset=UTF-8”)  
  3.     public String h1(HttpServletRequest req, HttpServletResponse res) throws Exception {  
  4.         UserBean user= …;        
  5.         ObjectMapper mapper = new ObjectMapper();  
  6.         String js=mapper.writeValueAsString(user);  
  7.         return js;  
  8.     }  
@ResponseBody    @RequestMapping(value = "/list", method = RequestMethod.GET,produces = "text/json;charset=UTF-8")    public String h1(HttpServletRequest req, HttpServletResponse res) throws Exception {        UserBean user= ...;              ObjectMapper mapper = new ObjectMapper();        String js=mapper.writeValueAsString(user);        return js;    }


形式二

[java] view plain copy
print?
  1. @ResponseBody  
  2.     @RequestMapping(value = “/list”, method = RequestMethod.GET)  
  3.     public void list(HttpServletRequest req, HttpServletResponse res) throws Exception {  
  4.         res.setContentType(”text/json;charset=UTF-8”);  
  5.         UserBean user= …;  
  6.         ObjectMapper mapper = new ObjectMapper();  
  7.         String js=mapper.writeValueAsString(user);  
  8.         PrintWriter pWriter = res.getWriter();  
  9.         pWriter.write(js);  
  10.     }  
@ResponseBody    @RequestMapping(value = "/list", method = RequestMethod.GET)    public void list(HttpServletRequest req, HttpServletResponse res) throws Exception {        res.setContentType("text/json;charset=UTF-8");        UserBean user= ...;        ObjectMapper mapper = new ObjectMapper();        String js=mapper.writeValueAsString(user);        PrintWriter pWriter = res.getWriter();        pWriter.write(js);    }


4.Spring4整合MyBatis3

说明:《Spring实战(第4版)》并没有提到MyBatis的整合,这个是我自己写的,写一起只为查看方便。

新建MybatisConfig文件

[java] view plain copy
print?
  1. import javax.sql.DataSource;  
  2. import org.mybatis.spring.SqlSessionFactoryBean;  
  3. import org.mybatis.spring.mapper.MapperScannerConfigurer;  
  4. import org.springframework.context.annotation.Bean;  
  5. import org.springframework.context.annotation.Configuration;  
  6. import org.springframework.jdbc.datasource.DataSourceTransactionManager;  
  7. import org.springframework.jdbc.datasource.DriverManagerDataSource;  
  8. import org.springframework.transaction.PlatformTransactionManager;  
  9. import org.springframework.transaction.annotation.EnableTransactionManagement;  
  10.   
  11. @Configuration  
  12. @EnableTransactionManagement  
  13. public class MybatisConfig {  
  14.   
  15.     @Bean  
  16.     public DataSource dataSource() {  
  17.         DriverManagerDataSource dataSource = new DriverManagerDataSource();  
  18.         dataSource.setUsername(”admin”);  
  19.         dataSource.setPassword(”admin”);  
  20.         dataSource.setDriverClassName(”com.microsoft.sqlserver.jdbc.SQLServerDriver”);//如果其他数据库换对应的驱动即可  
  21.         dataSource.setUrl(”jdbc:sqlserver://blog.csdn.net.unix21:3499;DatabaseName=testdb”);  
  22.         return dataSource;  
  23.     }  
  24.   
  25.     @Bean  
  26.     MapperScannerConfigurer mpperScannnerConfigurer() {  
  27.         MapperScannerConfigurer msc = new MapperScannerConfigurer();  
  28.         msc.setSqlSessionFactoryBeanName(”sqlSessionFactory”);  
  29.         msc.setBasePackage(”com.unix.mapper”);//自动扫描mapper包  
  30.         return msc;  
  31.     }  
  32.   
  33.     @Bean(name = “sqlSessionFactory”)  
  34.     SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {  
  35.         SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();  
  36.         ssfb.setDataSource(dataSource);  
  37.         ssfb.setTypeAliasesPackage(”com.unix.bean”);//自动扫描bean包  
  38.         return ssfb;  
  39.     }  
  40.   
  41.     @Bean  
  42.     PlatformTransactionManager transactionManager(DataSource dataSource) {  
  43.         DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();  
  44.         transactionManager.setDataSource(dataSource);  
  45.         return transactionManager;  
  46.     }  
  47. }  
import javax.sql.DataSource;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.mapper.MapperScannerConfigurer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.jdbc.datasource.DriverManagerDataSource;import org.springframework.transaction.PlatformTransactionManager;import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration@EnableTransactionManagementpublic class MybatisConfig {    @Bean    public DataSource dataSource() {        DriverManagerDataSource dataSource = new DriverManagerDataSource();        dataSource.setUsername("admin");        dataSource.setPassword("admin");        dataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");//如果其他数据库换对应的驱动即可        dataSource.setUrl("jdbc:sqlserver://blog.csdn.net.unix21:3499;DatabaseName=testdb");        return dataSource;    }    @Bean    MapperScannerConfigurer mpperScannnerConfigurer() {        MapperScannerConfigurer msc = new MapperScannerConfigurer();        msc.setSqlSessionFactoryBeanName("sqlSessionFactory");        msc.setBasePackage("com.unix.mapper");//自动扫描mapper包        return msc;    }    @Bean(name = "sqlSessionFactory")    SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();        ssfb.setDataSource(dataSource);        ssfb.setTypeAliasesPackage("com.unix.bean");//自动扫描bean包        return ssfb;    }    @Bean    PlatformTransactionManager transactionManager(DataSource dataSource) {        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();        transactionManager.setDataSource(dataSource);        return transactionManager;    }}

新增一个mapper接口

[java] view plain copy
print?
  1. public interface  SchoolMapper {  
  2.     @Select(“select * from School where id =#{id}”)  
  3.     School findById(@Param(“id”int id);  
  4.       
  5.     @Select(“select * from School where Name like ’${name}%’”)  
  6.     List<School> findByName(@Param(“name”) String name);  
  7. }  
public interface  SchoolMapper {    @Select("select * from School where id =#{id}")    School findById(@Param("id") int id);    @Select("select * from School where Name like '${name}%'")    List<School> findByName(@Param("name") String name);}

测试用例

[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = MybatisConfig.class)  
  3. //@TransactionConfiguration(defaultRollback=true)  
  4. public class SchoolTest {  
  5.     @Autowired  
  6.     private SchoolMapper shoolDao;  
  7.       
  8.     @Test  
  9.     public void findById(){  
  10.         School shool = shoolDao.findById(1);  
  11.         Assert.assertNotNull(shool);  
  12.         System.out.println(shool.getName());         
  13.     }  
  14.       
  15.     @Test  
  16.     public void findByName(){  
  17.         List<School> result = shoolDao.findByName(”苏州中学”);  
  18.         Assert.assertNotNull(result);  
  19.         for (School s : result) {  
  20.         System.out.println(s.getName());  
  21.         }          
  22.     }  
  23. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = MybatisConfig.class)//@TransactionConfiguration(defaultRollback=true)public class SchoolTest {    @Autowired    private SchoolMapper shoolDao;    @Test    public void findById(){        School shool = shoolDao.findById(1);        Assert.assertNotNull(shool);        System.out.println(shool.getName());           }    @Test    public void findByName(){        List<School> result = shoolDao.findByName("苏州中学");        Assert.assertNotNull(result);        for (School s : result) {        System.out.println(s.getName());        }            }}


5.Spring4使用Redis

redis在日常开发中已经成为了标配了,在spring4中使用redis非常简单,无需自己去写一个jedis的工厂方法连接池之类的代码,因为Spring已经写好了,你只需要引用spring-data-redis包即可

[html] view plain copy
print?
  1. <dependency>  
  2.             <groupId>org.springframework.data</groupId>  
  3.             <artifactId>spring-data-redis</artifactId>  
  4.             <version>1.7.1.RELEASE</version>  
  5.         </dependency>  
<dependency>            <groupId>org.springframework.data</groupId>            <artifactId>spring-data-redis</artifactId>            <version>1.7.1.RELEASE</version>        </dependency>

Redis配置

[java] view plain copy
print?
  1. @Configuration  
  2. public class RedisConfig {  
  3.   
  4.     @Bean  
  5.     public RedisConnectionFactory redisCF() {  
  6.         JedisConnectionFactory cf = new JedisConnectionFactory();  
  7.         cf.setHostName(”127.0.0.1”);//服务器IP  
  8.         cf.setPort(6379);//端口  
  9.         cf.setPassword(”密码”);  
  10.         return cf;  
  11.     }  
  12.   
  13.     @Bean  
  14.     public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {  
  15.         RedisTemplate<String, String> redis = new RedisTemplate<String, String>();  
  16.         redis.setConnectionFactory(cf);  
  17.         return redis;  
  18.     }  
  19.       
  20.     @Bean  
  21.     public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory cf) {  
  22.         StringRedisTemplate redis = new StringRedisTemplate();  
  23.         redis.setConnectionFactory(cf);  
  24.         return redis;  
  25.     }  
  26. }  
@Configurationpublic class RedisConfig {    @Bean    public RedisConnectionFactory redisCF() {        JedisConnectionFactory cf = new JedisConnectionFactory();        cf.setHostName("127.0.0.1");//服务器IP        cf.setPort(6379);//端口        cf.setPassword("密码");        return cf;    }    @Bean    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {        RedisTemplate<String, String> redis = new RedisTemplate<String, String>();        redis.setConnectionFactory(cf);        return redis;    }    @Bean    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory cf) {        StringRedisTemplate redis = new StringRedisTemplate();        redis.setConnectionFactory(cf);        return redis;    }}

测试用例

[java] view plain copy
print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = RedisConfig.class)  
  3. public class RedisTest {  
  4.     @Autowired  
  5.     private StringRedisTemplate r1;  
  6.     @Test  
  7.     public void get() {  
  8.           
  9.         String foo=DateUtil.getNowTimeString();  
  10.         r1.opsForValue().set(”foo”, foo);  
  11.           
  12.         foo=r1.opsForValue().get(”foo”);  
  13.         System.out.println(”【Redis 测试>>>get set】”+foo+“By http://blog.csdn.net/unix21”);  
  14.     }  
  15. }  
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = RedisConfig.class)public class RedisTest {    @Autowired    private StringRedisTemplate r1;    @Test    public void get() {        String foo=DateUtil.getNowTimeString();        r1.opsForValue().set("foo", foo);        foo=r1.opsForValue().get("foo");        System.out.println("【Redis 测试>>>get set】"+foo+"By http://blog.csdn.net/unix21");    }}


6.Spring Security


[html] view plain copy
print?
  1. import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;  
  2.   
  3. public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {  
  4. }  
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {}

[java] view plain copy
print?
  1. @Configuration  
  2. @EnableWebMvcSecurity  
  3. public class SecuredConfig extends WebSecurityConfigurerAdapter {  
  4.   
  5.     @Override  
  6.     protected void configure(HttpSecurity http) throws Exception {  
  7.       
  8.     http  
  9.         .authorizeRequests()  
  10.             .anyRequest().authenticated()  
  11.             .and()  
  12.         .formLogin()  
  13.             .and()  
  14.         .httpBasic();  
  15.       
  16.     }  
  17.   
  18. }  
@Configuration@EnableWebMvcSecuritypublic class SecuredConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {    http        .authorizeRequests()            .anyRequest().authenticated()            .and()        .formLogin()            .and()        .httpBasic();    }}


这个时候访问任何页面都会跳转到系统自带的登陆页面

基于内存的用户存储:

[java] view plain copy
print?
  1. //基于内存的用户  
  2. @Override  
  3. protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
  4.     auth  
  5.             .inMemoryAuthentication()  
  6.             .withUser(”user1”).password(“pass1”).roles(“USER”).and()  
  7.             .withUser(”user2”).password(“pass2”).roles(“USER”,“ADMIN”);  
  8. }  
    //基于内存的用户    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        auth                .inMemoryAuthentication()                .withUser("user1").password("pass1").roles("USER").and()                .withUser("user2").password("pass2").roles("USER","ADMIN");    }


故意输错用户名密码就进不去


验证 指定页面+指定权限

[java] view plain copy
print?
  1. @Override  
  2. protected void configure(HttpSecurity http) throws Exception {  
  3.     http  
  4.           .authorizeRequests()  
  5.               .antMatchers(”/news”).hasRole(“USER”)  
  6.               .and()  
  7.           .formLogin()  
  8.             .and()  
  9.             .httpBasic();  
  10. }  
    @Override    protected void configure(HttpSecurity http) throws Exception {        http              .authorizeRequests()                  .antMatchers("/news").hasRole("USER")                  .and()              .formLogin()                .and()                .httpBasic();    }



我们设定/news需要User角色的用户可以看,其他页面随便看


我们用user2登陆,由于没权限返回403


只有用user1登陆才可以看到页面内容。


自定义登陆页

现实开发中不肯能用Spring提供的简易登陆页,除非是一个很小的内部系统。

[java] view plain copy
print?
  1. @Configuration  
  2. @EnableWebMvcSecurity  
  3. public class SecuredConfig extends WebSecurityConfigurerAdapter {  
  4.   
  5.     @Override  
  6.     protected void configure(HttpSecurity http) throws Exception {  
  7.         http  
  8.                 .authorizeRequests()  
  9.                 .antMatchers(”/news/*”).hasRole(“USER”)    
  10.                 .and()  
  11.                 .formLogin()  
  12.                 .loginPage(”/login”)  
  13.                 .defaultSuccessUrl(”/”)  
  14.                 .failureUrl(”/login?error”)  
  15.                 .permitAll()  
  16.                 .and()  
  17.                 .httpBasic();  
  18.     }  
@Configuration@EnableWebMvcSecuritypublic class SecuredConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        http                .authorizeRequests()                .antMatchers("/news/*").hasRole("USER")                  .and()                .formLogin()                .loginPage("/login")                .defaultSuccessUrl("/")                .failureUrl("/login?error")                .permitAll()                .and()                .httpBasic();    }

.antMatchers(“/news/*”).hasRole(“USER”)   :匹配  /news/以及/news/ 开头的所有页面  需要USER权限

.loginPage(“/login”)   :自定义登陆页
.defaultSuccessUrl(“/”)   :默认成功页,如果没有权限则跳转到该页面

 .failureUrl(“/login?error”)  :默认失败页面


[java] view plain copy
print?
  1. // 1. /login 登录页面的常规显示  
  2. // 2. /login?error 登录验证失败的展示  
  3. // 3. /login?logout 注销登录的处理  
  4. @RequestMapping(value = “/login”, method = RequestMethod.GET)  
  5. public ModelAndView login(  
  6.         @RequestParam(value = “error”, required = false) String error,  
  7.         @RequestParam(value = “logout”, required = false) String logout) {  
  8.   
  9.     ModelAndView model = new ModelAndView();  
  10.     if (error != null) {  
  11.         model.addObject(”error”“用户名密码不对!”);  
  12.     }  
  13.   
  14.     if (logout != null) {  
  15.         model.addObject(”msg”“You’ve been logged out successfully.”);  
  16.     }  
  17.     model.setViewName(”login”);  
  18.   
  19.     return model;  
  20.   
  21. }  
      // 1. /login 登录页面的常规显示    // 2. /login?error 登录验证失败的展示    // 3. /login?logout 注销登录的处理    @RequestMapping(value = "/login", method = RequestMethod.GET)    public ModelAndView login(            @RequestParam(value = "error", required = false) String error,            @RequestParam(value = "logout", required = false) String logout) {        ModelAndView model = new ModelAndView();        if (error != null) {            model.addObject("error", "用户名密码不对!");        }        if (logout != null) {            model.addObject("msg", "You've been logged out successfully.");        }        model.setViewName("login");        return model;    }

login.jsp

[java] view plain copy
print?
  1. <%@page contentType=“text/html” pageEncoding=“UTF-8”%>  
  2. <html>  
  3.     <head>  
  4.         <title>登陆</title>  
  5.     </head>  
  6.     <body onload=’document.f.username.focus();’>  
  7.         <h3>登陆页</h3>          
  8.          <c:if test={not&nbsp;empty&nbsp;error}"</span><span>&gt;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div&nbsp;&nbsp;style=<span class="string">"color:&nbsp;red"</span><span>&gt;{error}</div>  
  9.          </c:if>  
  10.          <c:if test={not&nbsp;empty&nbsp;msg}"</span><span>&gt;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;div&gt;{msg}</div>  
  11.          </c:if>  
  12.         <form name=’f’ action=‘/gkweb/login’ method=‘POST’>  
  13.             <table>  
  14.                 <tr><td>用户名:</td><td><input type=’text’ name=‘username’ value=></td></tr>  
  15.                 <tr><td>密码:</td><td><input type=’password’ name=‘password’/></td></tr>  
  16.                 <tr><td colspan=’2’><input name=“submit” type=“submit” value=“登陆”/></td></tr>                 
  17.             </table>  
  18.             <input type=”hidden” name={_csrf.parameterName}"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value=<span class="string">"{_csrf.token}” />  
  19.         </form>  
  20.     </body>  
  21. </html>  
<%@page contentType="text/html" pageEncoding="UTF-8"%><html>    <head>        <title>登陆</title>    </head>    <body onload='document.f.username.focus();'>        <h3>登陆页</h3>                 <c:if test="${not empty error}">             <div  style="color: red">${error}</div>         </c:if>         <c:if test="${not empty msg}">            <div>${msg}</div>         </c:if>        <form name='f' action='/gkweb/login' method='POST'>            <table>                <tr><td>用户名:</td><td><input type='text' name='username' value=''></td></tr>                <tr><td>密码:</td><td><input type='password' name='password'/></td></tr>                <tr><td colspan='2'><input name="submit" type="submit" value="登陆"/></td></tr>                           </table>            <input type="hidden" name="${_csrf.parameterName}"                value="${_csrf.token}" />        </form>    </body></html>
此处参考:http://www.mkyong.com/spring-security/spring-security-form-login-example/


配置多个页面权限控制

[java] view plain copy
print?
  1. .antMatchers(“/news/*”,“/user/*”).hasRole(“USER”)  
.antMatchers("/news/*","/user/*").hasRole("USER")

写法二

[cpp] view plain copy
print?
  1. .antMatchers(“/news/*”).hasRole(“USER”)  
  2. .antMatchers(”/user/*”).hasRole(“USER”)  
.antMatchers("/news/*").hasRole("USER").antMatchers("/user/*").hasRole("USER")
可以将任意多的antMatchers(),anyRequest()连接起来,但是这些规则会按给定的顺序发挥作用,所以需要将最为具体的请求路径放在最前面,而最不具体的路径anyRequest()放在后面,不然不具体的就会覆盖掉具体的。


[java] view plain copy
print?
  1. @Override  
  2. protected void configure(HttpSecurity http) throws Exception {  
  3.     http  
  4.         .authorizeRequests()  
  5.             .antMatchers(”/”“/home”).permitAll()  
  6.             .anyRequest().authenticated()  
  7.             .and()  
  8.         .formLogin()  
  9.             .loginPage(”/login”)  
  10.             .defaultSuccessUrl(”/helloadmin”)  
  11.             .permitAll()  
  12.             .and()  
  13.         .logout()  
  14.             .permitAll();  
  15. }  
    @Override    protected void configure(HttpSecurity http) throws Exception {        http            .authorizeRequests()                .antMatchers("/", "/home").permitAll()                .anyRequest().authenticated()                .and()            .formLogin()                .loginPage("/login")                .defaultSuccessUrl("/helloadmin")                .permitAll()                .and()            .logout()                .permitAll();    }

对URL进行权限配置,使得”/”, “/home”不需要登录就可以访问,其他需要登录。登录的地址是’/login’,当登录成功后将跳转到/helloadmin页面,并且登录、登出页面都是不需要登录就可以访问的。

参考:使用Spring Security进行权限验证


.httpBasic()

支持弹窗就是windows自带的认证框进行认证。由于不好扩展这个基本没什么用,可以不用。


.rememberMe()

记住我的状态

[java] view plain copy
print?
  1. .rememberMe().key(“web”)  
  2.                     .tokenValiditySeconds(1209600);  
.rememberMe().key("web")                    .tokenValiditySeconds(1209600);

.logout()

注销功能

[java] view plain copy
print?
  1. @Override  
  2.    protected void configure(HttpSecurity http) throws Exception {  
  3.        http  
  4.                .authorizeRequests()  
  5.                    .antMatchers(”/news/*”).hasRole(“USER”)  
  6.                    .and()  
  7.                .formLogin()  
  8.                    .loginPage(”/login”)  
  9.                    .defaultSuccessUrl(”/”)  
  10.                    .failureUrl(”/login?error”)  
  11.                    .usernameParameter(”username”)  
  12.                    .passwordParameter(”password”)  
  13.                    .and()  
  14.                .logout()  
  15.                    .logoutSuccessUrl(”/login?logout”)  
  16.                    .and()  
  17.                .rememberMe().key(”gkweb”)  
  18.                    .tokenValiditySeconds(1209600);  
  19.    }  
 @Override    protected void configure(HttpSecurity http) throws Exception {        http                .authorizeRequests()                    .antMatchers("/news/*").hasRole("USER")                    .and()                .formLogin()                    .loginPage("/login")                    .defaultSuccessUrl("/")                    .failureUrl("/login?error")                    .usernameParameter("username")                    .passwordParameter("password")                    .and()                .logout()                    .logoutSuccessUrl("/login?logout")                    .and()                .rememberMe().key("gkweb")                    .tokenValiditySeconds(1209600);    }

注销就是页面给用户一个链接或者按钮

1.使用jstl声明退出路径

引用jar包

[html] view plain copy
print?
  1. <dependency>  
  2.             <groupId>jstl</groupId>  
  3.             <artifactId>jstl</artifactId>  
  4.             <version>1.2</version>  
  5.         </dependency>  
<dependency>            <groupId>jstl</groupId>            <artifactId>jstl</artifactId>            <version>1.2</version>        </dependency>

[html] view plain copy
print?
  1. <%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c” %>  
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
[html] view plain copy
print?
  1. <c:url var=“logoutUrl” value=“/logout”/>  
  2. <form action={logoutUrl}"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="attribute">method</span><span>=</span><span class="attribute-value">"post"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="tag">&lt;</span><span class="tag-name">input</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"submit"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="attribute">value</span><span>=</span><span class="attribute-value">"Log&nbsp;out"</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="tag">&lt;</span><span class="tag-name">input</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"hidden"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="attribute">name</span><span>=</span><span class="attribute-value">"{_csrf.parameterName}”  
  3.     value=“${_csrf.token}”/>  
  4. </form>  
<c:url var="logoutUrl" value="/logout"/><form action="${logoutUrl}"    method="post"><input type="submit"    value="Log out" /><input type="hidden"    name="${_csrf.parameterName}"    value="${_csrf.token}"/></form>


2.硬编码退出路径

[html] view plain copy
print?
  1. <form action={pageContext.request.contextPath}/logout"</span><span>&nbsp;</span><span class="attribute">method</span><span>=</span><span class="attribute-value">"post"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">input</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"submit"</span><span>&nbsp;</span><span class="attribute">value</span><span>=</span><span class="attribute-value">"Logout"</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">input</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"hidden"</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="attribute">name</span><span>=</span><span class="attribute-value">"{_csrf.parameterName}”  
  2.     value={_csrf.token}"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="tag">&lt;/</span><span class="tag-name">form</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li></ol></div><pre code_snippet_id="1672099" snippet_file_name="blog_20160520_60_5247108" name="code" class="html" style="display: none;">&lt;form action="{pageContext.request.contextPath}/logout” method=”post”> <input type=”submit” value=”Logout” /> <input type=”hidden” name=”csrf.parameterNamevalue={_csrf.token}”/></form>

    3.链接退出

    [html] view plain copy
    print?
    1. <script>  
    2.         function formSubmit() {  
    3.             document.getElementById(“logoutForm”).submit();  
    4.         }  
    5.     </script>  
    6.   
    7. <form action={pageContext.request.contextPath}/logout"</span><span>&nbsp;</span><span class="attribute">method</span><span>=</span><span class="attribute-value">"post"</span><span>&nbsp;</span><span class="attribute">id</span><span>=</span><span class="attribute-value">"logoutForm"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">c:if</span><span>&nbsp;</span><span class="attribute">test</span><span>=</span><span class="attribute-value">"{pageContext.request.userPrincipal.name != null}”>  
    8.       <h2>  
    9.         Welcome : {pageContext.request.userPrincipal.name}&nbsp;|&nbsp;<span class="tag">&lt;</span><span class="tag-name">a</span><span>&nbsp;</span><span class="attribute">href</span><span>=</span><span class="attribute-value">"javascript:formSubmit()"</span><span class="tag">&gt;</span><span>&nbsp;退出1-链接</span><span class="tag">&lt;/</span><span class="tag-name">a</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;/</span><span class="tag-name">h2</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;/</span><span class="tag-name">c:if</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">input</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"submit"</span><span>&nbsp;</span><span class="attribute">value</span><span>=</span><span class="attribute-value">"退出1-按钮"</span><span>&nbsp;</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">input</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"hidden"</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"{_csrf.parameterName}” value={_csrf.token}"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;/</span><span class="tag-name">form</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">c:url</span><span>&nbsp;</span><span class="attribute">var</span><span>=</span><span class="attribute-value">"logoutUrl"</span><span>&nbsp;</span><span class="attribute">value</span><span>=</span><span class="attribute-value">"/logout"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">form</span><span>&nbsp;</span><span class="attribute">action</span><span>=</span><span class="attribute-value">"{logoutUrl}” method=“post”>  
    10.             <c:if test={pageContext.request.userPrincipal.name&nbsp;!=&nbsp;null}"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tag">&lt;</span><span class="tag-name">h2</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Welcome&nbsp;:&nbsp;{pageContext.request.userPrincipal.name} | <a href=“javascript:formSubmit()”> 退出2-链接</a>  
    11.       </h2>  
    12.     </c:if>  
    13.               
    14.             <input type=“submit” value=“退出2-按钮” />  
    15.             <input type=“hidden” name={_csrf.parameterName}"</span><span>&nbsp;</span><span class="attribute">value</span><span>=</span><span class="attribute-value">"{_csrf.token}”/>  
    16.         </form>  
    <script>        function formSubmit() {            document.getElementById("logoutForm").submit();        }    </script><form action="${pageContext.request.contextPath}/logout" method="post" id="logoutForm">            <c:if test="${pageContext.request.userPrincipal.name != null}">      <h2>        Welcome : ${pageContext.request.userPrincipal.name} | <a href="javascript:formSubmit()"> 退出1-链接</a>      </h2>    </c:if>            <input type="submit" value="退出1-按钮" />            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>        </form>        <c:url var="logoutUrl" value="/logout"/>        <form action="${logoutUrl}" method="post">            <c:if test="${pageContext.request.userPrincipal.name != null}">      <h2>        Welcome : ${pageContext.request.userPrincipal.name} | <a href="javascript:formSubmit()"> 退出2-链接</a>      </h2>    </c:if>            <input type="submit" value="退出2-按钮" />            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>        </form>

    自定义的用户服务

    实际开发肯定是需要去数据库或者其他地方查询用户账号密码等

    [java] view plain copy
    print?
    1. @Override  
    2.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
    3.         auth.userDetailsService(new CustomUserDetailsService(userDao));  
    4. }  
    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        auth.userDetailsService(new CustomUserDetailsService(userDao));}


    注意:CustomUserDetailsService需要的bean一定要从userDetailsService调用CustomUserDetailsService的构造器传递过去,

    而不能直接在CustomUserDetailsService使用@Autowired注解出来。
     

    CustomUserDetailsService集成的接口UserDetailsService无需自己重新定义,参考 泛型推断类型不符合上限

    [java] view plain copy
    print?
    1. public class CustomUserDetailsService implements UserDetailsService {  
    2.   
    3.     private final UserMapper userDao;  
    4.     public CustomUserDetailsService(UserMapper u) {  
    5.         this.userDao = u;  
    6.     }  
    7.   
    8.     @Override  
    9.     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {         
    10.         UserBean user = userDao.findByName(username);          
    11.         if (user == null) {  
    12.             throw new UsernameNotFoundException(“没有找到对应用户”);  
    13.         }  
    14.         List<SimpleGrantedAuthority> authorities = new ArrayList<>();  
    15.         authorities.add(new SimpleGrantedAuthority(user.getUtype().toString()));  
    16.         return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), authorities);  
    17.     }  
    18. }  
    public class CustomUserDetailsService implements UserDetailsService {    private final UserMapper userDao;    public CustomUserDetailsService(UserMapper u) {        this.userDao = u;    }    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {               UserBean user = userDao.findByName(username);                if (user == null) {            throw new UsernameNotFoundException("没有找到对应用户");        }        List<SimpleGrantedAuthority> authorities = new ArrayList<>();        authorities.add(new SimpleGrantedAuthority(user.getUtype().toString()));        return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), authorities);    }}

    跨站攻击

    Spring Security3.2开始默认是开启的的,如果有特殊要求可以关闭跨站防御

    [java] view plain copy
    print?
    1. .csrf().disable();  
    .csrf().disable();


    多权限组合

    需要注意要以页面为单位,不然下面的配置会和上面的冲突

    [java] view plain copy
    print?
    1. .authorizeRequests()  
    2.                     .antMatchers(”/news/*”,“/school/*”).hasAnyRole(“1”,“4”)  
    3.                     .antMatchers(”/goods/*”).hasRole(“4”)  
    4.                     .and()  
    .authorizeRequests()                    .antMatchers("/news/*","/school/*").hasAnyRole("1","4")                    .antMatchers("/goods/*").hasRole("4")                    .and()


    自定义403页面

    [java] view plain copy
    print?
    1. http.authorizeRequests()  
    2.         .antMatchers(”/admin/**”).access(“hasRole(‘ROLE_ADMIN’)”)  
    3.         .and().formLogin()  
    4.         .loginPage(”/login”).failureUrl(“/login?error”)  
    5.         .usernameParameter(”username”)  
    6.         .passwordParameter(”password”)  
    7.         .and().logout().logoutSuccessUrl(”/login?logout”)  
    8.         .and()  
    9.         .exceptionHandling().accessDeniedPage(”/403”)  
    10.     }  
    http.authorizeRequests()        .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")        .and().formLogin()        .loginPage("/login").failureUrl("/login?error")        .usernameParameter("username")        .passwordParameter("password")        .and().logout().logoutSuccessUrl("/login?logout")        .and()        .exceptionHandling().accessDeniedPage("/403")    }

    然后自己写一个SpringMVC的/403页面即可

    参考:Spring Security : Customize 403 access denied page


    自定义404页面

    其实这个是SpringMVC干的事情,非常简单

    定义一个

    [java] view plain copy
    print?
    1. @RequestMapping(value = “*”, method = RequestMethod.GET)  
    2. public String my404() {  
    3.     return “404”;  
    4. }  
        @RequestMapping(value = "*", method = RequestMethod.GET)    public String my404() {        return "404";    }


    POST参数中文乱码的解决

    注意,如果没有使用Springsecurity,那么可以直接在SpingWebInitializer定义一个getServletFilters()

    如下:

    [java] view plain copy
    print?
    1. import javax.servlet.Filter;  
    2. import org.springframework.web.filter.CharacterEncodingFilter;  
    3. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;  
    4.   
    5. public class SpingWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {  
    6.   
    7.     @Override  
    8.     protected Class<?>[] getRootConfigClasses() {  
    9.         return new Class<?>[]{RootConfig.class};  
    10.     }  
    11.   
    12.     @Override  
    13.     protected Class<?>[] getServletConfigClasses() {  
    14.         return new Class<?>[]{WebConfig.class};  
    15.     }  
    16.   
    17.     @Override  
    18.     protected String[] getServletMappings() {  
    19.         return new String[]{“/”};  
    20.     }  
    21.          
    22.     @Override  
    23.     protected Filter[] getServletFilters() {  
    24.         CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();  
    25.         characterEncodingFilter.setEncoding(”UTF-8”);  
    26.         characterEncodingFilter.setForceEncoding(true);  
    27.         return new Filter[] { characterEncodingFilter};  
    28.     }  
    29. }  
    import javax.servlet.Filter;import org.springframework.web.filter.CharacterEncodingFilter;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class SpingWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {    @Override    protected Class<?>[] getRootConfigClasses() {        return new Class<?>[]{RootConfig.class};    }    @Override    protected Class<?>[] getServletConfigClasses() {        return new Class<?>[]{WebConfig.class};    }    @Override    protected String[] getServletMappings() {        return new String[]{"/"};    }    @Override    protected Filter[] getServletFilters() {        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();        characterEncodingFilter.setEncoding("UTF-8");        characterEncodingFilter.setForceEncoding(true);        return new Filter[] { characterEncodingFilter};    }}


    如果使用了Springsecurity,那么需要在Springsecurity的配置文件里配置,因为CharacterEncodingFilter 需要在 SecurityFilter之前启动

    [cpp] view plain copy
    print?
    1. public class SecuredConfig extends WebSecurityConfigurerAdapter {  
    2. @Override  
    3.     protected void configure(HttpSecurity http) throws Exception {  
    4.         //The CharacterEncodingFilter must be started before SecurityFilter. I moved it to security configuration:  
    5.         CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();  
    6.         encodingFilter.setEncoding(”UTF-8”);  
    7.         encodingFilter.setForceEncoding(true);  
    8.         http.addFilterBefore(encodingFilter,CsrfFilter.class);  
    9. … …  
    public class SecuredConfig extends WebSecurityConfigurerAdapter {@Override    protected void configure(HttpSecurity http) throws Exception {        //The CharacterEncodingFilter must be started before SecurityFilter. I moved it to security configuration:        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();        encodingFilter.setEncoding("UTF-8");        encodingFilter.setForceEncoding(true);        http.addFilterBefore(encodingFilter,CsrfFilter.class);... ...



原创粉丝点击