spring-day4

第四天:

1  aop:config标签
   使用aop的专用标签来完成相关的配置.
   其中主要表现是使用AspectJ的expression的操作:
   execution(modifiers-pattern ret-type-pattern declaring-type-pattern name-pattern(param-pattern) throws-pattern)除了返回类型模式,名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 *,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型
   
   注意在使用之前需要在xml文件的beans标签中加入新的schame文件:并在Eclipse中进行关联配置
   <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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.2.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">


   下面给出一些常见切入点表达式的例子。  

 
   1)任意包下的任意类中的公共方法的执行:  
      execution(public * *(..))
   2)任何一个以“set”开始的方法的执行:  
      execution(* set*(..))
   3)AccountService 接口的任意方法的执行:    
      execution(* com.briup.service.AccountService.*(..))
   4)定义在service包里的任意方法的执行:  
      execution(* com.briup.service.*.*(..))
   5)定义在service包或者子包里的任意方法的执行:  
      execution(* com.briup.service..*.*(..))
   6)在service包里的任意连接点(在Spring AOP中只是方法执行)
      within(com.xyz.service.*)
   7)在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :  
      within(com.xyz.service..*)



   注意:  1.从spring容器中拿代理对象的时候也是要用目标对象的名字来拿。
      2.没有实现任何接口的目标对象也能产生代理对象。
    
        <!-- 配置aop的代理 -->
    <aop:config>
        <!-- 定义一个切入点 并给切入点起名为myPointCut -->
        <!-- 切入点是一组连接点的集合 -->
        <aop:pointcut expression="execution(public * com.briup.aop.service.*.*(..))" id="myPointCut"/>

        <!-- 定义哪一个advice在哪一个切入点上面起作用 -->
        <aop:advisor advice-ref="beforeAdvice" pointcut-ref="myPointCut" />
    </aop:config>
    <!--
        expression="execution(public * com.briup.spring.aop.service.*.*(..))"
        这个引号""里面就是用表达式的方式来定义切入点,只要是符合我们这个表达式要求的
        方法就是我们的连接点,连接点的集合就是我们要定义的切入点。
        表达式中从左到右的*号:
            第一个* 表示方法的返回类型不限。
            第二个* 表示包中的任意一个类
            第三个* 表示类中的任意一个方法
            
        同时方法的参数也没有限制.
     -->

2  在一个切面类中定个多个方法,根据xml文件的配置每个方法都可以织入到切入点的不同位置,并且advice是在aop的标签中进行配置,不需要再写对应的advice类了
   例如:
    //这个类相当于我们之前的切面类
    //只不过这个切面类中有很多方法都可以织入到切入点上面
    //我们可以控制把这里的任何一个方法织入到任何一个切入点上面
    public class XmlHandler {
        
        public void beforeTest(JoinPoint p){
            System.out.println(p.getSignature().getName()+" before...");
        }
        
        
        public void afterTest(JoinPoint p){
            System.out.println(p.getSignature().getName()+" after...");
        }
        
        public void afterReturningTest(JoinPoint p){
            
            System.out.println(p.getSignature().getName()+" afterReturning");
            
        }
        
        //在和aroundAdvice结合的时候,这个方法一定要加上这个ProceedingJoinPoint类型的参数
        public Object aroundTest(ProceedingJoinPoint pjp)throws Throwable{
            //JoinPoint对象不能调用连接点所表示的方法
            //ProceedingJoinPoint能调用连接点所表示的方法 pjp.proceed()
            System.out.println(pjp.getSignature().getName()+" is start..");
            //调用到连接点方法
            Object obj = pjp.proceed();
            System.out.println(pjp.getSignature().getName()+" is end..");
            return obj;
        }
        
        public void throwingTest(JoinPoint p,Exception ex){
            System.out.println(p.getSignature().getName()+" is throwing..."+ex.getMessage());
            
        }
    }
    
        xml文件配置:
    <!-- 配置dao层对象 -->
    <bean id="dao"
        class="com.briup.aop.dao.AccountDaoImpl"/>
     <!-- 配置目标对象 -->
    <bean name="target"
    class="com.briup.aop.service.AccountServiceImpl">
            <property name="accountDao" ref="dao"></property>
    </bean>
    <!-- 配置切面类 -->
    <bean name="handler" class="com.briup.aop.xml.XmlHandler"></bean>
    
    <!-- 配置aop的代理 -->
    <aop:config>
        <!-- 定义切入点名为myPointCut -->
        <aop:pointcut expression="execution(public * com.briup.aop.service.*.*(..))" id="myPointCut"/>
        
        <!-- 定义切面类 以及需要使用的advice -->
        <aop:aspect id="aspect" ref="handler">
            <!-- 表示beforeAdvice会把切面类handler中的beforeTest方法织入到名字叫myPointCut的切入点上面 -->
            <aop:before method="beforeTest" pointcut-ref="myPointCut"/>

            <!-- after表示不管方法是否正常结束都会起作用 -->
            <aop:after method="afterTest" pointcut-ref="myPointCut"/>

            <!-- after-returning表示方法正常结束才会起作用(抛异常时候不起作用) -->
            <aop:after-returning method="afterReturningTest" pointcut-ref="myPointCut"/>

            <aop:around method="aroundTest" pointcut-ref="myPointCut"/>

            <!-- throwing="ex"表示throwingTest方法中接收异常对象的名字一定要是ex -->
            <aop:after-throwing method="throwingTest" pointcut-ref="myPointCut" throwing="ex"/>

        </aop:aspect>
    </aop:config>



3  使用注解配置AOP:其实就是在上面的类XmlHandler中加入上注解然后去掉xml中的aop标签配置,这里把类改名为AnnotationHandler,
   例子:
    @Component
    @Aspect
    public class AnnotationHandler {
        /*
         * 在一个方法上面加上注解来定义切入点
         * 这个切入点的名字就是这个方法的名字
         * 这个方法本身不需要有什么作用
         * 这个方法的意义就是:给这个 @Pointcut注解一个可以书写的地方
         * 因为注解只能写在方法、属性、类的上面,并且方法名作为切入点的名字
         * */
        @Pointcut("execution(public * com.briup.aop.service..*.*(..))")
        public void myPointCut(){}
        
        //注:这里面的所有方法的JoinPoint类型对象都可以去掉不写
        @Before("myPointCut()")
        public void beforeTest(JoinPoint p){
            System.out.println(p.getSignature().getName()+" before...");
        }
        
        
        /*
         * @After和@AfterReturning
         *
         * @After标注的方法会在切入点上的方法结束后被调用(不管是不是正常的结束).
         * @AfterReturning标注的方法只会在切入点上的方法正常结束后才被调用.
         * */
        @After("myPointCut()")
        public void afterTest(JoinPoint p){
            System.out.println(p.getSignature().getName()+" after...");
        }
        @AfterReturning("myPointCut()")
        public void afterReturningTest(JoinPoint p){
            
            System.out.println(p.getSignature().getName()+" afterReturning");
            
        }
        
        @Around("myPointCut()")
        public Object aroundTest(ProceedingJoinPoint pjp)throws Throwable{
            System.out.println(pjp.getSignature().getName()+" is start..");
            //调用连接点的方法去执行
            Object obj = pjp.proceed();
            System.out.println(pjp.getSignature().getName()+" is end..");
            return obj;
        }
        
        
        
        //在切入点中的方法执行期间抛出异常的时候,会调用这个 @AfterThrowing注解所标注的方法
        @AfterThrowing(value="myPointCut()",throwing="ex")
        public void throwingTest(JoinPoint p,Exception ex){
            System.out.println(p.getSignature().getName()+" is throwing..."+ex.getMessage());
            
        }
        
        
    }
    
    xml配置:注意给例子中使用的其他的类上面也使用注解
    <aop:aspectj-autoproxy/>
    <context:component-scan base-package="com.briup.aop"/>


4  Spring与jdbc结合
   jdbc编程不变,主要是Connection对象的维护,即配置并使用数据源
   1)   <!-- 基于jdk的规范数据源 -->
        <bean name="dataSource1"
        class="oracle.jdbc.pool.OracleConnectionPoolDataSource">
        <property name="networkProtocol">
            <value>tcp</value>
        </property>
        <property name="databaseName">
            <value>XE</value>
        </property>
        <property name="driverType">
            <value>thin</value>
        </property>
        <property name="portNumber">
            <value>1521</value>
        </property>
        <property name="user">
            <value>briup</value>
        </property>
        <property name="serverName">
            <value>127.0.0.1</value>
        </property>
        <property name="password">
            <value>briup</value>
        </property>
    </bean>


   注意:别忘了读取配置文件
    <!-- 读取这个资源文件 读完之后下面就可以用${key}来去文件中的value值了 -->
    <!-- 这种方式是我们第一节学习的那种配置方式方式的简写 -->
    <context:property-placeholder location="com/briup/db/jdbc/jdbc.properties"/>

   2)    <!-- dbcp数据源 -->
    <bean id="dataSource2"
        class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName">
            <value>${jdbc.driverClassName}</value>
        </property>
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
        <!-- 最大连接数 -->
        <property name="maxActive">
            <value>80</value>
        </property>
        <!-- 最大空闲连接数 -->
        <property name="maxIdle">
            <value>20</value>
        </property>
        <!-- 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间 单位:毫秒 -->
        <!-- 超过时间则抛出异常,如果设置为-1表示无限等待 -->
        <property name="maxWait">
            <value>3000</value>
        </property>
    </bean>

   3)  <!-- spring提供的一种数据源 -->
       <bean id="dataSource3"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>${jdbc.driverClassName}</value>
        </property>
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
      </bean>

    spring在jdbc的使用中还给我们提供了一个模板类:JdbcTemplate
    用以简化我们的jdbc操作
    例如:
    //使用xml进行配置时候的java类中的写法:
    public class JdbcTemplateDao implements AccountDao{
    private JdbcTemplate jdbcTemplate;
    
    //只要类中有set方法 在xml文件就可以进行配置和注入
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    ...
    }
   
    //使用注解进行配置时候的java类中的写法:
    @Repository
    public class JdbcTemplateDao implements AccountDao {

        private JdbcTemplate jdbcTemplate;

        @Autowired
        public void setDataSource(DataSource dataSource) {
                this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    ....
    ...
    }

    注意:JdbcTemplate模板类如何使用:在htmlsingle中搜索即可,其中包含有大量的使用实例



5  Spring与Hibernate结合
   使用Spring整合Hibernate时我们可以不需要hibernate.cfg.xml文件。
   
   重点在于配置sessionFactory
    <!-- 配置sessionFactory -->
    <bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
        name="sessionFactory">
        <!-- 注入数据源 -->
        <property name="dataSource">
               <ref local="dataSource"/>
        </property>
        <!-- 注入映射文件-->
        <property name="mappingResources">
               <list>
                    <value>com/briup/db/hibernate/account.hbm.xml</value>
               </list>
        </property>
        <!-- 注入hibernate的属性信息-->
        <property name="hibernateProperties">
               <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
               </props>
        </property>
    </bean>
        
    或者:

    <!-- 配置sessionFactory -->
    <bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
        name="sessionFactory">
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
    </bean>

    结合hibernate的配置xml例子:
        <bean id="account" class="com.briup.db.Account"/>
    
    <!-- 配置sessionFactory -->
    <bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
        name="sessionFactory">
         <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
         </property>
    </bean>
    <!-- 配置dao层对象 -->
    <bean name="accountDao"
          class="com.briup.db.hibernate.Spring_Hibernate">
          <!-- 注入sessionFactory对象 -->
          <property name="sessionFactory">
             <ref bean="sessionFactory" />
          </property>
      </bean>
      
      <!-- 配置hibernate的事务管理器 相当于aop配置中的切面类-->
      <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          <!-- 注入sessionFactory对象 -->
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>
    
    <!-- 配置事务拦截器 相当于aop配置中advice-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 配置在些方法上面加入哪些事务属性 以及抛出什么异常的时候回滚-->
            <tx:method name="with*" propagation="REQUIRED" rollback-for="Throwable"/>
            <tx:method name="depo*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 上面配置了切面类以及advice -->
    <!-- 这里就要做aop的配置了 -->
    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut id="myPointCut"
        expression="execution(* com.briup.db.hibernate..*.*(..))"/>
        <!-- 配置事务拦截器在哪一个切入点上起作用 -->
        <aop:advisor pointcut-ref="myPointCut" advice-ref="txAdvice"/>
    </aop:config>

    和jdbc类似的spirng也提供了hibernate的模板类的使用:HibernateTemplate
    使用过程和jdbc的模板类差不多,在htmlsingle有实例说明




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过在Spring Security中配置一个Token认证过滤器来实现基于WebSocket的Token认证。具体步骤如下: 1. 创建一个TokenAuthenticationFilter类,继承自OncePerRequestFilter并实现doFilterInternal方法。该类负责检查请求中是否包含有效的Token,并进行相应的认证处理。 ```java public class TokenAuthenticationFilter extends OncePerRequestFilter { private final TokenProvider tokenProvider; public TokenAuthenticationFilter(TokenProvider tokenProvider) { this.tokenProvider = tokenProvider; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = getTokenFromRequest(request); if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) { Authentication authentication = tokenProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String getTokenFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } } ``` 2. 创建一个TokenProvider类,用于生成Token和验证Token的有效性,并根据Token获取用户信息。 ```java @Component public class TokenProvider { private static final String SECRET_KEY = "my-secret-key"; private static final long EXPIRATION_TIME = 86400000; // 1 day public String generateToken(Authentication authentication) { UserPrincipal principal = (UserPrincipal) authentication.getPrincipal(); Date expirationDate = new Date(System.currentTimeMillis() + EXPIRATION_TIME); return Jwts.builder() .setSubject(Long.toString(principal.getId())) .setIssuedAt(new Date()) .setExpiration(expirationDate) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; } catch (Exception e) { return false; } } public Authentication getAuthentication(String token) { Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); Long userId = Long.parseLong(claims.getSubject()); UserPrincipal principal = new UserPrincipal(userId); return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); } } ``` 3. 在配置类中注册TokenAuthenticationFilter和TokenProvider,并将TokenAuthenticationFilter添加到Spring Security的过滤器链中。 ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Autowired private TokenProvider tokenProvider; @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").setAllowedOriginPatterns("*").withSockJS(); } @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(new ChannelInterceptorAdapter() { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); if (StompCommand.CONNECT.equals(accessor.getCommand())) { String token = accessor.getFirstNativeHeader("Authorization"); if (StringUtils.hasText(token) && token.startsWith("Bearer ")) { token = token.substring(7); TokenAuthenticationFilter filter = new TokenAuthenticationFilter(tokenProvider); SecurityContextHolder.getContext().setAuthentication(filter.getAuthentication(token)); } } return message; } }); } @Override public void configureClientOutboundChannel(ChannelRegistration registration) { } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { } @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { } @Override public boolean configureMessageConverters(List<MessageConverter> messageConverters) { return true; } @Override public void configureWebSocketTransport(WebSocketTransportRegistration registry) { } @Bean public TokenAuthenticationFilter tokenAuthenticationFilter() throws Exception { TokenAuthenticationFilter filter = new TokenAuthenticationFilter(tokenProvider); filter.setAuthenticationManager(authenticationManager()); return filter; } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable().authorizeRequests() .antMatchers("/api/auth/**").permitAll() .anyRequest().authenticated(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override @Bean public UserDetailsService userDetailsService() { return new UserDetailsServiceImpl(); } } ``` 在上述代码中,我们通过重写configureClientInboundChannel方法,在连接到WebSocket时获取请求中的Token,并使用TokenAuthenticationFilter进行认证。注意,我们需要将TokenAuthenticationFilter添加到Spring Security的过滤器链中,以便它能够在WebSocket连接期间对请求进行拦截。 最后,我们需要在客户端的连接请求中添加Authorization头部,以便在服务端进行Token认证。例如: ```javascript stompClient.connect({}, function(frame) { console.log('Connected: ' + frame); stompClient.subscribe('/topic/greetings', function(greeting) { showGreeting(JSON.parse(greeting.body).content); }); }, function(error) { console.log('Error: ' + error); }, {"Authorization": "Bearer " + token}); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值