Spring,Java:获取关键错误配置的电子邮件。

时间:2015-10-30 12:21:24

标签: java spring email spring-mvc email-integration

我正在开发一个Spring-MVC项目,我正在寻找为关键后端错误添加一些电子邮件工具。

因此,例如,如果在执行CRUD操作时存在NPE或某些数据库异常,那么对于那些。不是因为它们可能是网络错误,因为网络在该客户端和服务器之间丢失。

我知道如何实现这一目标的唯一方法是添加try-catch块并使用stacktrace在catch块中发送电子邮件,但这不实用,因为代码库很大并且有很多方法。

请让我知道我能做些什么来使这更容易,更优雅。当然我可以自己编写发送电子邮件代码,但是如何触发此方法并将堆栈跟踪发送到此方法是我的问题。 我发布我的配置文件,如果这有帮助。

root-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>

security-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>

我希望问题很清楚。如果您有什么想知道的话。请告诉我。非常感谢。 : - )

2 个答案:

答案 0 :(得分:3)

我建议使用日志记录框架来处理错误的记录和报告,而不是自己在应用程序代码中处理它。

任何好的日志记录框架(LogbackLog4j,...)都会为您提供某种SMTP appender。您可以将此appender与常规文件/控制台appender配置,并将其根级别设置为ERROR,以确保只通过电子邮件发送错误。您可以通过实施filter并将其用于SMTP appender来进一步过滤错误。

查看this post以获取用于忽略指定类型的异常的过滤器的示例。

以下是文档中Logback的SMTP appender示例配置:

<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>

这样做的好处是它可以在整个应用程序中普遍使用。使用Spring MVC的Exception处理程序在注释中建议的解决方案仅在由于调用某个控制器而发生错误时才有效。但是,您可能会收到意外错误,您希望在预定作业和其他组件中收到通知。

答案 1 :(得分:1)

Spring MVC提供了为控制器提供自定义异常处理程序的机制。 这可以使用@ExceptionHandler注释,例如

@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);
}

您可以将此魔术方法放在基本控制器(将是所有控制器的超类),特定控制器或"controller advice"中。

有关详细信息,请参阅此博客文章:https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc