javascript
使用AspectJ审计Spring MVC Webapp。 第2部分
現(xiàn)在,如果您有興趣創(chuàng)建一個(gè)以Aspectj的@Aspect和@Before批注的形式使用面向方面編程(AOP)的Spring MVC Webapp來(lái)審核用戶對(duì)屏幕的訪問(wèn),那么這是您想要閱讀的博客。
正如我在上一個(gè)博客中所說(shuō)的那樣,審核用戶對(duì)屏幕的訪問(wèn)是面向方面編程(AOP)很好解決的少數(shù)幾個(gè)交叉問(wèn)題之一。 就我的演示代碼而言,其想法是,您將注釋添加到適當(dāng)?shù)目刂破?#xff0c;并且每次用戶訪問(wèn)頁(yè)面時(shí),都會(huì)記錄該訪問(wèn)。 使用此技術(shù),您可以構(gòu)建最流行的屏幕的圖片,從而構(gòu)建應(yīng)用程序中最流行的功能塊。 知道了這些細(xì)節(jié)之后,就可以更輕松地決定將開(kāi)發(fā)目標(biāo)放在何處,因?yàn)殚_(kāi)發(fā)幾乎沒(méi)有人使用過(guò)的那些應(yīng)用程序塊是沒(méi)有用的。
對(duì)于演示代碼,我創(chuàng)建了一個(gè)簡(jiǎn)單的Spring MVC應(yīng)用程序,該應(yīng)用程序具有兩個(gè)屏幕:主頁(yè)和幫助頁(yè)面。 在此之上,我創(chuàng)建了一個(gè)簡(jiǎn)單的批注: @Audit ,用于將控制器標(biāo)記為需要審計(jì)的控制器(并非所有控制器都需要,尤其是如果您選擇審計(jì)功能點(diǎn)而不是單個(gè)屏幕時(shí)),并且告訴建議對(duì)象的屏幕ID。 我已經(jīng)在下面的代碼片段中演示了這一點(diǎn):
@Audit("Home") @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) {在停留在AspectJ方面之前,首先要做的是使用為工作設(shè)計(jì)的Spring模板創(chuàng)建標(biāo)準(zhǔn)的Spring MVC Web應(yīng)用程序:
下一步要做的就是對(duì)POM文件進(jìn)行一堆更改,如我之前的博客中所述 。 這些并不是一切必不可少的,它們對(duì)于一切正常工作都是必不可少的。 但是,請(qǐng)確保您添加了aspectJwearver依賴項(xiàng)并刪除了AspectJ插件定義。
該應(yīng)用程序具有兩個(gè)控制器和兩個(gè)簡(jiǎn)單??的JSP。 第一個(gè)控制器是從Spring MVC應(yīng)用程序中獲取的HomeController ,第二個(gè)控制器是旨在在應(yīng)用程序的任何頁(yè)面上顯示幫助的HelpController 。 我在下面包括了HelpController的showHelp(…)方法,但這只是為了完整性。 在這種情況下,只要有幾個(gè)要審核的控制器實(shí)際上沒(méi)有關(guān)系。
@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"; }從上面的代碼中,您可以看到我的兩個(gè)RequestMapping方法都使用@Audit注釋進(jìn)行了注釋,因此下一步是其定義:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Audit { String value(); }此代碼的關(guān)鍵是保留策略和目標(biāo)。 保留策略必須設(shè)置為RetentionPolicy.RUNTIME ,這意味著編譯器不會(huì)丟棄注釋,并確保在運(yùn)行時(shí)將注釋保存在JVM中。 @Target定義可以在何處應(yīng)用注釋。 在這種情況下,我只希望將其應(yīng)用于方法,因此目標(biāo)是ElementType.METHOD 。 注釋必須包含一個(gè)值,在這種情況下,該值用于保存用戶當(dāng)前正在訪問(wèn)的屏幕的名稱。
下一個(gè)關(guān)鍵抽象是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()); } }這有兩個(gè)AspectJ注釋: @Aspect和@Before 。 @Aspect批注將AuditAdvice類標(biāo)記為一個(gè)方面 ,而@Before批注意味著在定義與作為@Before批注的參數(shù)的表達(dá)式匹配的任何方法之前,將調(diào)用auditScreen(…)方法。
這種表達(dá)是很酷的想法。 我已經(jīng)在Spring應(yīng)用程序中使用AspectJ的@AfterThrowing建議中的博客中介紹了execution表達(dá)式的構(gòu)造; 但是,總而言之,我將對(duì)所有具有公共可見(jiàn)性,返回String且位于com.captaindebug.audit.controller程序包中并且將單詞Controller包含@Before方法都應(yīng)用@Before注釋方法。班級(jí)名稱。 換句話說(shuō),我很難將此執(zhí)行表達(dá)式應(yīng)用于除我的應(yīng)用程序的控制器以外的任何對(duì)象,并且這些控制器必須由@Audit注釋進(jìn)行注釋,如@annotation(auditAnnotation)表達(dá)式和auditScreen(…)方法的Audit auditAnnotation參數(shù)。 這意味著我不能無(wú)意中將@Audit注釋?xiě)?yīng)用于除控制器之外的任何東西
AuditAdvice類將實(shí)際審核的職責(zé)委托給AuditService 。 這是一項(xiàng)虛擬服務(wù),因此與其執(zhí)行諸如將審核事件存儲(chǔ)在數(shù)據(jù)庫(kù)中之類的有用操作,不如將其簡(jiǎn)單地添加到日志文件中。
@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"; } }因此,這就是本文所涵蓋的代碼,現(xiàn)在剩下要做的就是整理Spring配置文件,在這里沒(méi)有太多要做。 首先,與任何AOP應(yīng)用程序一樣,您需要添加以下AOP啟用行:
<aop:aspectj-autoproxy/>…連同其架構(gòu)詳細(xì)信息:
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"其次,您需要通過(guò)更新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>您還可以選擇從架構(gòu)位置URI的末尾刪除版本號(hào)。 例如:
http://www.springframework.org/schema/context/spring-context.3.0.xsd變成:
http://www.springframework.org/schema/context/spring-context.xsd這樣做的原因是,由于沒(méi)有任何版本號(hào)的架構(gòu)URI似乎指向該架構(gòu)的最新版本,因此它在將來(lái)的某個(gè)時(shí)刻簡(jiǎn)化了Spring版本的升級(jí)。
為了完整起見(jiàn),我的配置文件如下所示:
<?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>最后,當(dāng)您運(yùn)行該應(yīng)用程序時(shí),將記錄用戶對(duì)主頁(yè)的訪問(wèn)。 當(dāng)用戶單擊幫助鏈接時(shí),也會(huì)記錄對(duì)幫助頁(yè)面的訪問(wèn)。 日志文件中的輸出如下所示:
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 有關(guān)此代碼和下一個(gè)博客的代碼,請(qǐng)?jiān)L問(wèn)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
總結(jié)
以上是生活随笔為你收集整理的使用AspectJ审计Spring MVC Webapp。 第2部分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 铁岭是几线城市(辽宁第3大市比沈阳还大是
- 下一篇: 茅台真假的识别方法(茅台酒真假鉴别方法图