基于Maven的SSM总体架构设计(五)
3.4.9 引入log4j,完善日志输出体系
为了跟踪程序的运行状况,方便调试。日志是必不可少的。Log4j是目前最流行的日志框架,几乎所有的其他框架都用到了log4j,具体使用步骤如下:
1、在src/main/resources下增加log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- ========================== 自定义输出格式说明================================ -->
<!-- %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL -->
<!-- #%r 输出自应用启动到输出该log信息耗费的毫秒数 -->
<!-- #%c 输出所属的类目,通常就是所在类的全名 -->
<!-- #%t 输出产生该日志事件的线程名 -->
<!-- #%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” -->
<!-- #%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日
22:10:28,921 -->
<!-- #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10) -->
<!-- ========================================================================== -->
<!-- ========================== 输出方式说明================================ -->
<!-- Log4j提供的appender有以下几种: -->
<!-- org.apache.log4j.ConsoleAppender(控制台), -->
<!-- org.apache.log4j.FileAppender(文件), -->
<!-- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件), -->
<!-- org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件), -->
<!-- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) -->
<!-- ========================================================================== -->
<!-- 输出到日志文件 每天一个日志 -->
<appender name="filelog_daily" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${pass}logs/mesnac_logs_daily.log" />
<param name="DatePattern" value="'daily.'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d{yyyy-MM-dd HH:mm:ss\} %-5p] [%t] (%c:%L) - %m%n" />
</layout>
</appender>
<!-- 输出到控制台中 -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss\} %-5p] (%c:%L) - %m%n" />
<!-- <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p: %m%n" /> -->
<!-- "%-5p: [%t] [%c{3}.%M(%L)] | %m%n" -->
</layout>
<!-- 限制日志输出级别 -->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="ERROR" />
<param name="LevelMin" value="TRACE" />
</filter>
</appender>
<!-- 发邮件(只有ERROR时才会发送) -->
<appender name="mail" class="org.apache.log4j.net.SMTPAppender">
<param name="threshold" value="ERROR" />
<!-- 缓存文件大小,日志达到512k时发送Email -->
<param name="BufferSize" value="512" />
<param name="From" value="[email protected]" />
<param name="SMTPHost" value="smtp.126.com" />
<param name="Subject" value="Archimedes-log4jMessage" />
<param name="To" value="[email protected]" />
<param name="SMTPUsername" value="zhenglibingaccp" />
<param name="SMTPPassword" value="qibing791014" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss.SSS} [%p]-[%c] %m%n" />
</layout>
</appender>
<!-- 通过<category></category>的定义可以将各个包中的类日志输出到不同的日志文件中-->
<!--
<category name="com.mesnac" additivity="false">
<level value="INFO" />
<appender-ref ref="filelog_daily" />
<appender-ref ref="console" />
<appender-ref ref="mail" />
</category>
-->
<root>
<level value="DEBUG" />
<!-- <appender-ref ref="filelog_appender" /> -->
<!-- <appender-ref ref="filelog_daily" /> -->
<appender-ref ref="console" />
</root>
</log4j:configuration>
2、修改web.xml,增加对log4j的支持
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.xml</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
3、编写日志服务类com.mesnac.util.LogService
package com.mesnac.util;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
/**
* 功能说明:日志记录服务类
* 修改说明:
* @author zhenglibing
* @date 2017-4-25 下午4:01:24
* @version V0.1
*/
public final class LogService {
private static LogService instance;
private static Logger logger = null;
private static Map<Class, Logger> loggerList = new HashMap<Class, Logger>(); //用于缓存logger对象
/**
* 定义私有构造方法实现单例
*/
private LogService() {
}
/**
* 功能说明:获取服务实例的静态方法
* 修改说明:
* @author zhenglibing
* @date 2017-4-25 下午4:02:09
* @param obj 传入调用此方法的对象
* @return
*/
public synchronized static LogService getInstance(Object obj) {
if (instance == null) {
instance = new LogService();
}
LogService.logger = loggerList.get(obj.getClass());
if (LogService.logger == null) {
LogService.logger = Logger.getLogger(obj.getClass());
loggerList.put(obj.getClass(), LogService.logger);
}
return instance;
}
/**
* 功能说明:获取服务实例的静态方法
* 修改说明:
* @author zhenglibing
* @date 2017-4-25 下午4:03:10
* @param clazz 传入调用此方法的类型
* @return
*/
public synchronized static LogService getInstance(Class clazz) {
if (instance == null) {
instance = new LogService();
}
LogService.logger = loggerList.get(clazz);
if (LogService.logger == null) {
LogService.logger = Logger.getLogger(clazz);
loggerList.put(clazz, LogService.logger);
}
return instance;
}
/**
* 功能说明:获取服务实例的静态方法
* 修改说明:
* @author zhenglibing
* @date 2017-4-25 下午4:05:13
* @return
*/
public synchronized static LogService getInstance() {
if (instance == null) {
instance = new LogService();
}
LogService.logger = loggerList.get(LogService.class);
if (LogService.logger == null) {
LogService.logger = Logger.getLogger(LogService.class);
loggerList.put(LogService.class, LogService.logger);
}
return instance;
}
public void trace(Object message) {
LogService.logger.trace(message);
}
public void trace(Object message, Throwable t) {
LogService.logger.trace(message, t);
}
public void debug(Object message) {
LogService.logger.debug(message);
}
public void debug(Object message, Throwable t) {
LogService.logger.debug(message, t);
}
public void info(Object message) {
LogService.logger.info(message);
}
public void info(Object message, Throwable t) {
LogService.logger.info(message, t);
}
public void warn(Object message) {
LogService.logger.warn(message);
}
public void warn(Object message, Throwable t) {
LogService.logger.warn(message, t);
}
public void error(Object message) {
LogService.logger.error(message);
}
public void error(Object message, Throwable t) {
LogService.logger.error(message, t);
}
}
4、编写日志服务测试类,运行测试
public class LogServiceTestCase {
@Test
public void testDebug() {
LogService.getInstance(this).debug("This is Debug log");
}
@Test
public void testInfo() {
LogService.getInstance(this).info("This is Info log");
}
@Test
public void testWarn() {
LogService.getInstance(this).warn("This is warn log");
}
@Test
public void testError() {
LogService.getInstance(this).error("This is error log");
}
}
5、在dao、service、action中使用LogService
3.4.10 引入Shiro,实现身份验证与授权访问
直接说使用步骤吧:
1、在pom.xml中增加shiro依赖库
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.1</version>
</dependency>
2、在src/main/java下增加Realm相关代码
3、在src/main/resources下增加ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<defaultCache maxElementsInMemory="10000" eternal="false"
overflowToDisk="false" timeToIdleSeconds="500" timeToLiveSeconds="1000"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120" />
<cache name="shiroAuthorizationCache" maxElementsInMemory="10000"
eternal="false" overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="120" timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120" />
</ehcache>
4、在src/main/resources下增加spring-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.2.xsd ">
<!-- 启用缓存注解功能(请将其配置在Spring主配置文件中) -->
<cache:annotation-driven cache-manager="cacheManager"/>
<!-- ehcache 的配置 -->
<!-- Spring提供的基于的Ehcache实现的缓存管理器 -->
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManagerFactory"/>
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="cacheManagerFactory"/>
</bean>
<!-- 配置ModularRealmAuthenticator,可以实现多Realm认证 -->
<!-- <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> -->
<bean id="authenticator" class="com.wongoing.sys.shiro.ShiroMulityModularRealmAuthenticator">
<!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 -->
<property name="authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
</property>
</bean>
<!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的MesnacShiroRealm.java -->
<bean id="shiroUserRealm" class="com.wongoing.sys.shiro.ShiroUserRealm">
<property name="cacheManager" ref="shiroCacheManager"/>
<property name="authenticationCacheName" value="shiroAuthorizationCache"></property>
<!--配置密码匹配器-->
<property name="credentialsMatcher">
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密算法可以为MD5、SHA-1、SHA-256、SHA-512,此处使用的SHA-1 -->
<property name="hashAlgorithmName" value="SHA-1" />
<!-- 加密次数 -->
<property name="hashIterations" value="1024" />
</bean>
</property>
</bean>
<!-- Shiro默认会使用Servlet容器的Session,可通过sessionMode属性来指定使用Shiro原生Session -->
<!-- 即<property name="sessionMode" value="native"/>,详细说明见官方文档 -->
<!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 以下为单realm配置 -->
<!--<property name="realm" ref="shiroRealm"/>-->
<property name="authenticator" ref="authenticator"/>
<!--可以配置多个Realm,其实会把realms属性赋值给ModularRealmAuthenticator的realms属性 -->
<property name="realms">
<list>
<ref bean="shiroUserRealm" />
</list>
</property>
</bean>
<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 -->
<!-- Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"/>
<!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
<property name="loginUrl" value="/start.jsp"/>
<!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码为main.jsp了) -->
<property name="successUrl" value="/index.jsp"/>
<!-- 用户访问未对其授权的资源时,所显示的连接 -->
<!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp -->
<property name="unauthorizedUrl" value="/"/>
<property name="filterChainDefinitions">
<value>
/favicon.ico = anon
/Kaptcha.jpg = anon
/release/** = anon
/resources/** = anon
/resources/frontPage/** = anon
/extend/** = anon
/druid/** = anon
/start.jsp = anon
/error.jsp = anon
/fail.jsp = anon
/upload/** = anon
/img/** = anon
/jsp/system/login.jsp = anon
/sys/sysUserAction/login = anon
/ws/** = anon
/front/** = anon
/front2/** = anon
/** = authc
</value>
</property>
</bean>
</beans>
5、修改web.xml增加对shiro的支持
<!-- 配置Spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml,classpath:spring-shiro.xml</param-value>
</context-param>
<!-- 配置Shiro过滤器,先让Shiro过滤系统接收到的请求 -->
<!-- 这里filter-name必须对应applicationContext.xml中定义的<bean id="shiroFilter"/> -->
<!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 -->
<!-- 通常会将此filter-mapping放置到最前面(即其他filter-mapping前面),以保证它是过滤器链中第一个起作用的 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6、通过Subject来进行认证和授权
7、菜单权限-MesnacShiroRealm
8、菜单权限-index.jsp
9、操作权限-MesnacShrioRealm
10、操作权限-xxx.jsp
<%@ taglib uri=“http://shiro.apache.org/tags” prefix=“shiro” %>
<shrio:hasPermission name=“”></shiro:hasPermission>
<shiro:guest>我的账户</shiro:guest>
<shiro:user><shiro:principal /></shiro:user>
(未完待续…)
完整资料下载