现在,如果您有兴趣创建一个以Aspectj的@Aspect
和@Before
批注的形式使用面向方面编程(AOP)的Spring MVC Webapp来审核用户对屏幕的访问,那么这是您想要阅读的博客。
正如我在上一个博客中所说的那样,审核用户对屏幕的访问是面向方面编程(AOP)很好解决的少数几个交叉问题之一。 就我的演示代码而言,其想法是,您将注释添加到适当的控制器,并且每次用户访问页面时,都会记录该访问。 使用此技术,您可以构建最流行的屏幕的图片,从而构建应用程序中最流行的功能块。 知道了这些细节之后,就可以更轻松地决定将开发目标放在何处,因为开发几乎没有人使用过的那些应用程序块是没有用的。
对于演示代码,我创建了一个简单的Spring MVC应用程序,该应用程序具有两个屏幕:主页和帮助页面。 在此之上,我创建了一个简单的批注: @Audit
,用于将控制器标记为需要审计的控制器(并非所有控制器都需要,尤其是如果您选择审计功能点而不是单个屏幕时),并且告诉建议对象的屏幕ID。 我已经在下面的代码片段中演示了这一点:
@Audit("Home") @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) {
在停留在AspectJ方面之前,首先要做的是使用为工作设计的Spring模板创建标准的Spring MVC Web应用程序:
下一步要做的就是对POM文件进行一堆更改,如我之前的博客中所述 。 这些并不是一切必不可少的,它们对于一切正常工作都是必不可少的。 但是,请确保您添加了aspectJwearver
依赖项并删除了AspectJ插件定义。
该应用程序具有两个控制器和两个简单的JSP。 第一个控制器是从Spring MVC应用程序中获取的HomeController
,第二个控制器是旨在在应用程序的任何页面上显示帮助的HelpController
。 我在下面包括了HelpController
的showHelp(…)
方法,但这只是为了完整性。 在这种情况下,只要有几个要审核的控制器实际上没有关系。
@Controller()
public class HelpController { @Audit("Help") // User has visited the help page @RequestMapping(value = "/help", method = RequestMethod.GET) public String showHelp(@RequestParam int pageId, Model model) { String help = getHelpPage(pageId); model.addAttribute("helpText", help); return "help"; }
从上面的代码中,您可以看到我的两个RequestMapping方法都使用@Audit
注释进行了注释,因此下一步是其定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audit { String value();
}
此代码的关键是保留策略和目标。 保留策略必须设置为RetentionPolicy.RUNTIME
,这意味着编译器不会丢弃注释,并确保在运行时将注释保存在JVM中。 @Target
定义可以在何处应用注释。 在这种情况下,我只希望将其应用于方法,因此目标是ElementType.METHOD
。 注释必须包含一个值,在这种情况下,该值用于保存用户当前正在访问的屏幕的名称。
下一个关键抽象是AuditAdvice
类,如下所示:
@Aspect
public class AuditAdvice { @Autowired private AuditService auditService; /** * Advice for auditing a user's visit to a page. The rule is that the Before annotation * applies to any method in any class in the com.captaindebug.audit.controller package * where the class name ends in 'Controller' and the method is annotated by @Audit. * * @param auditAnnotation * Audit annotation holds the name of the screen we're auditing. */ @Before("execution(public String com.captaindebug.audit.controller.*Controller.*(..)) && @annotation(auditAnnotation) ") public void myBeforeLogger(Audit auditAnnotation) { auditService.audit(auditAnnotation.value()); } }
这有两个AspectJ注释: @Aspect
和@Before
。 @Aspect
批注将AuditAdvice
类标记为一个方面 ,而@Before
批注意味着在定义与作为@Before
批注的参数的表达式匹配的任何方法之前,将调用auditScreen(…)
方法。
这种表达是很酷的想法。 我已经在Spring应用程序中使用AspectJ的@AfterThrowing建议中的博客中介绍了execution
表达式的构造; 但是,总而言之,我将对所有具有公共可见性,返回String且位于com.captaindebug.audit.controller
程序包中并且将单词Controller
包含@Before
方法都应用@Before
注释方法。班级名称。 换句话说,我很难将此执行表达式应用于除我的应用程序的控制器以外的任何对象,并且这些控制器必须由@Audit
注释进行注释,如@annotation(auditAnnotation)
表达式和auditScreen(…)
方法的Audit auditAnnotation
参数。 这意味着我不能无意中将@Audit
注释应用于除控制器之外的任何东西
AuditAdvice
类将实际审核的职责委托给AuditService
。 这是一项虚拟服务,因此与其执行诸如将审核事件存储在数据库中之类的有用操作,不如将其简单地添加到日志文件中。
@Service
public class AuditService { private static Logger logger = LoggerFactory.getLogger(AuditService.class); /** * Audit this screen against the current user name * * It's more useful to put this info into a database so that that you can count visits to * pages and figure out how often they're used. That way, you can focus your design on the * popular parts of your application. The logger is just for demo purposes. */ public void audit(String screenName) { String userName = getCurrentUser(); logger.info("Audit: {} - {}", userName, screenName); } /** * Get the current logged on user name by whatever mechanism available */ private String getCurrentUser() { return "Fred"; } }
因此,这就是本文所涵盖的代码,现在剩下要做的就是整理Spring配置文件,在这里没有太多要做。 首先,与任何AOP应用程序一样,您需要添加以下AOP启用行:
<aop:aspectj-autoproxy/>
…连同其架构详细信息:
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
其次,您需要通过更新context:components-scan
元素将建议类告知Spring上下文:
<context:component-scan base-package="com.captaindebug.audit"><context:include-filter type="aspectj"expression="com.captaindebug.audit.aspectj.AuditAdvice" /></context:component-scan>
您还可以选择从架构位置URI的末尾删除版本号。 例如:
http://www.springframework.org/schema/context/spring-context.3.0.xsd
变成:
http://www.springframework.org/schema/context/spring-context.xsd
这样做的原因是,由于没有任何版本号的架构URI似乎指向该架构的最新版本,因此它在将来的某个时刻简化了Spring版本的升级。
为了完整起见,我的配置文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure --><!-- Enables the Spring MVC @Controller programming model --><annotation-driven /><!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --><resources mapping="/resources/**" location="/resources/" /><!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --><beans:beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><beans:property name="prefix" value="/WEB-INF/views/" /><beans:property name="suffix" value=".jsp" /></beans:bean><aop:aspectj-autoproxy/><context:component-scan base-package="com.captaindebug.audit"><context:include-filter type="aspectj"expression="com.captaindebug.audit.aspectj.AuditAdvice" /></context:component-scan></beans:beans>
最后,当您运行该应用程序时,将记录用户对主页的访问。 当用户单击帮助链接时,也会记录对帮助页面的访问。 日志文件中的输出如下所示:
INFO : com.captaindebug.audit.service.AuditService - Audit: Fred - Home
INFO : com.captaindebug.audit.controller.HomeController - Welcome home! the client locale is en_US
INFO : com.captaindebug.audit.service.AuditService - Audit: Fred - Help
有关此代码和下一个博客的代码,请访问github: https : //github.com/roghughe/captaindebug/tree/master/audit-aspectj
翻译自: https://www.javacodegeeks.com/2013/07/auditing-a-spring-mvc-webapp-with-aspectj-part-2.html