2015-10-30 2 views
2

Je travaille sur un projet Spring-MVC pour lequel je cherche à ajouter un service de messagerie pour une erreur de backend critique. Ainsi, par exemple, s'il existe un NPE, ou des exceptions de base de données lors de l'exécution d'opérations CRUD, alors pour celles-ci. Pas pour les erreurs de réseau car elles pourraient être parce que le réseau est perdu entre ce client et serveur. La seule façon dont je sais comment y parvenir est d'ajouter des blocs try-catch et d'envoyer un email dans catch block avec stacktrace, mais ce n'est pas pratique car la base de code est grande et a beaucoup de méthodes. Veuillez me faire savoir ce que je peux faire pour rendre ceci plus facile et un peu plus élégant.Spring, Java: Obtenir des e-mails pour la configuration des erreurs critiques.

Bien sûr, je peux écrire moi-même l'e-mail d'envoi, mais comment déclencher cette méthode et envoyer la pile-trace à cette méthode est mon problème. Je poste mes fichiers de configuration, si cela peut vous aider.

racine context.xml:

<context:component-scan base-package="com.journaldev.spring"> 
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan> 

    <context:property-placeholder location="classpath:application.properties"/> 

    <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
       destroy-method="close"> 
     <beans:property name="driverClassName" value="org.postgresql.Driver"/> 
     <beans:property name="url" 
         value="jdbc:postgresql://localhost:5432/dbName"/> 
     <beans:property name="username" value="dbUser"/> 
     <beans:property name="password" value="dbpass"/> 
     <beans:property name="removeAbandoned" value="true"/> 
     <beans:property name="removeAbandonedTimeout" value="20"/> 
     <beans:property name="defaultAutoCommit" value="false"/> 
    </beans:bean> 

    <!-- Hibernate 4 SessionFactory Bean definition --> 
    <beans:bean id="hibernate4AnnotatedSessionFactory" 
       class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
     <beans:property name="dataSource" ref="dataSource"/> 
     <beans:property name="packagesToScan" value="com.journaldev.spring.model"/> 

     <beans:property name="hibernateProperties"> 
      <beans:props> 
       <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</beans:prop> 
       <beans:prop key="hibernate.show_sql">false</beans:prop> 
       <!-- <beans:prop key="hibernate.jdbc.batch_size">1000</beans:prop> 
        <beans:prop key="hibernate.order_updates">true</beans:prop>--> 
       <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop> 
       <beans:prop key="cache.use_second_level_cache">true</beans:prop> 
       <beans:prop key="cache.use_query_cache">true</beans:prop> 
      </beans:props> 
     </beans:property> 
    </beans:bean> 

    <beans:bean id="loginServiceImpl" class="com.journaldev.spring.service.LoginServiceImpl"/> 

    <task:annotation-driven/> 

    <tx:annotation-driven transaction-manager="transactionManager"/> 

    <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
     <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory"/> 
    </beans:bean> 

    <cache:annotation-driven /> 

    <beans:bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> 
     <beans:property name="caches"> 
      <beans:set> 
       <beans:bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" 
         p:name="person"/> 
      </beans:set> 
     </beans:property> 
    </beans:bean> 

    <!-- Configuration for Spring-Data-Redis --> 
    <beans:bean id="jedisConnFactory" 
       class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:usePool="true"/> 

    <beans:bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connectionFactory-ref="jedisConnFactory"/> 

    <!-- Jasypt configuration --> 
    <beans:bean id="stringEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor" lazy-init="false"> 
     <beans:property name="algorithm" value="algo" /> 
     <beans:property name="password" value="" /> 
    </beans:bean> 

    <beans:bean id="hibernateEncryptor" class="org.jasypt.hibernate4.encryptor.HibernatePBEStringEncryptor" lazy-init="false"> 

     <beans:property name="registeredName" value="jasyptHibernateEncryptor" /> 
     <beans:property name="encryptor" ref="stringEncryptor" /> 
    </beans:bean> 

servlet-context.xml:

<security:global-method-security 
      secured-annotations="enabled" 
      jsr250-annotations="disabled" 
      pre-post-annotations="enabled"/> 

    <context:component-scan base-package="com.journaldev.spring" use-default-filters="false"> 
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan> 

    <context:property-placeholder location="classpath:application.properties"/> 

    <mvc:annotation-driven> 
     <mvc:argument-resolvers> 
      <beans:bean class="org.springframework.mobile.device.DeviceWebArgumentResolver"/> 
     </mvc:argument-resolvers> 
    </mvc:annotation-driven> 
    <mvc:interceptors> 
     <beans:bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor"/> 
     <beans:ref bean="localeChangeInterceptor"/> 
    </mvc:interceptors> 

    <mvc:default-servlet-handler/> 

    <resources mapping="/resources/" location="/resources/"/> 

    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <beans:property name="prefix" value="/WEB-INF/views/"/> 
     <beans:property name="suffix" value=".jsp"/> 
    </beans:bean> 

    <!-- locale --> 
    <beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> 
     <beans:property name="basename" value="classpath:/locale/messages"/> 
     <beans:property name="defaultEncoding" value="UTF-8"/> 
    </beans:bean> 


    <!-- default locale --> 
    <beans:bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"> 
     <beans:property name="defaultLocale" value="de"/> 
    </beans:bean> 

    <!-- Change locale via url. --> 
    <beans:bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> 
     <beans:property name="paramName" value="lang"/> 
    </beans:bean> 

    <beans:bean id="handlerMapping" 
       class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"> 
     <beans:property name="interceptors"> 
      <beans:list> 
       <beans:ref bean="localeChangeInterceptor"/> 
      </beans:list> 
     </beans:property> 
    </beans:bean> 

    <beans:bean class="com.journaldev.spring.service.DoNotTruncateMyUrls"/> 

    <beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
     <beans:property name="maxUploadSize" value="52428800"/> 
    </beans:bean> 
    <!-- 52428800 --> 


</beans:beans> 

sécurité applicationContext.xml:

<security:http pattern="/resources/template/demo/clients" security="none"/> 

    <security:http create-session="ifRequired" use-expressions="true" auto-config="false" disable-url-rewriting="true"> 
     <security:form-login login-page="/login" username-parameter="j_username" password-parameter="j_password" 
          login-processing-url="/j_spring_security_check" default-target-url="/dashboard" 
          always-use-default-target="true" authentication-failure-url="/denied"/> 
     <security:remember-me key="_spring_security_remember_me" user-service-ref="userDetailsService" 
           token-validity-seconds="1209600" data-source-ref="dataSource"/> 
     <security:logout delete-cookies="JSESSIONID" invalidate-session="true" logout-url="/j_spring_security_logout"/> 
    <!--<security:intercept-url pattern="/**" requires-channel="https"/>--> 

     <security:port-mappings> 
      <security:port-mapping http="8080" https="8443"/> 
     </security:port-mappings> 
     <security:logout logout-url="/logout" logout-success-url="/" success-handler-ref="myLogoutHandler"/> 

     <security:session-management session-fixation-protection="migrateSession"> 
      <security:concurrency-control session-registry-ref="sessionReg" max-sessions="5" expired-url="/sessionExpired"/> 
     </security:session-management> 
    </security:http> 

    <beans:bean id="sessionReg" class="org.springframework.security.core.session.SessionRegistryImpl"/> 

    <beans:bean id="rememberMeAuthenticationProvider" 
       class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"> 
     <beans:constructor-arg index="0" value="_spring_security_remember_me"/> 
     <beans:constructor-arg index="1" ref="userDetailsService"/> 
     <beans:constructor-arg index="2" ref="jdbcTokenRepository"/> 
     <property name="alwaysRemember" value="true"/> 
    </beans:bean> 

    <beans:bean id="jdbcTokenRepository" 
       class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"> 
     <beans:property name="createTableOnStartup" value="false"/> 
     <beans:property name="dataSource" ref="dataSource"/> 
    </beans:bean> 

    <!-- Remember me ends here --> 
    <security:authentication-manager alias="authenticationManager"> 
     <security:authentication-provider user-service-ref="loginServiceImpl"> 
      <security:password-encoder ref="encoder"/> 
     </security:authentication-provider> 
    </security:authentication-manager> 

    <beans:bean id="encoder" 
       class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> 
     <beans:constructor-arg name="strength" value="11"/> 
    </beans:bean> 

    <beans:bean id="daoAuthenticationProvider" 
       class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> 
     <beans:property name="userDetailsService" ref="loginServiceImpl"/> 
     <beans:property name="passwordEncoder" ref="encoder"/> 
    </beans:bean> 
</beans> 

J'espère que la question est claire. S'il y a quelque chose que vous aimeriez savoir. Veuillez me le faire savoir. Merci beaucoup. :-)

+0

Je ne me souviens pas le nom exact mais il y a certains gestionnaire d'exceptions personnalisée (? '@ Advice') au printemps-mvc, il suffit de prendre un coup d'oeil à la doc . –

+0

@RC. : Voulez-vous dire '@Aspect'. Je ne trouve pas de Conseil en tant qu'annotation. –

+0

voir https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc –

Répondre

1

Spring MVC fournit des mécanismes pour disposer de gestionnaires d'exceptions personnalisés pour les contrôleurs. Cela fonctionne en utilisant l'annotation @ExceptionHandler, par exemple

@ExceptionHandler(value = IOException.class) 
public ResponseEntity<String> handleIOException(final IOException exception) { 
    log.error("Caught some IOException", exception); 
    return new ResponseEntity<String>(exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); 
} 

Vous pouvez mettre cette méthode magique dans un contrôleur de base (sera la superclasse de tous vos contrôleurs), dans un contrôleur ou dans un "controller advice" spécifique.

Voir ce billet de blog pour plus d'informations: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

+0

Merci beaucoup. :-) –

3

Je recommande d'utiliser un cadre de journalisation pour gérer la journalisation et la génération de rapports d'erreurs et ne pas les traiter vous-même dans le code de l'application. Toute bonne structure de journalisation (Logback, Log4j, ...) vous fournira une sorte d'appender SMTP. Vous pouvez configurer cet appender en même temps que vos appenders de fichiers/console et définir son niveau racine sur ERROR pour vous assurer que seules les erreurs seront envoyées par e-mail. Vous pouvez filtrer davantage les erreurs en implémentant un filter et en l'utilisant pour l'appender SMTP.

Extrayez this post pour un exemple de mise en œuvre d'un filtre pour ignorer les exceptions de type spécifié.

Voici un exemple de configuration de appender SMTP dans Logback de la documentation:

<configuration> 
    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"> 
     <filter class="com.example.YourExceptionFilter" /> 

     <smtpHost>ADDRESS-OF-YOUR-SMTP-HOST</smtpHost> 
     <to>EMAIL-DESTINATION</to> 
     <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible --> 
     <from>SENDER-EMAIL</from> 
     <subject>TESTING: %logger{20} - %m</subject> 
     <layout class="ch.qos.logback.classic.PatternLayout"> 
      <pattern>%date %-5level %logger{35} - %message%n</pattern> 
     </layout>  
    </appender> 

    <root level="ERROR"> 
     <appender-ref ref="EMAIL" /> 
    </root> 
</configuration> 

Ceci a l'avantage que cela fonctionnera universellement à travers toute votre application. La solution suggérée dans les commentaires utilisant les gestionnaires d'exceptions de Spring MVC ne fonctionnera que si l'erreur se produit à la suite de l'appel d'un contrôleur. Mais vous risquez d'obtenir une erreur inattendue dont vous souhaitez être averti dans les travaux planifiés et autres composants.

+0

Merci. Je vais vérifier cela. Je ne peux pas étendre car Java ne supporte pas l'héritage multiple, trouvera un filtre basé sur l'interface. Va commenter si j'ai un doute. –