- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
总的来说,我对 AspectJ 和 AOP 还很陌生。我确实知道 AspectJ 有很多注释(After、AfterReturning 等)来在调用方法之前、调用之后、返回之后、抛出异常时等执行代码。
我想用它来记录日志,这是一个非常典型的用例。我一直在看这篇文章,我认为这就是我所需要的。它使用 AspectJ 以及“jcambi方面”来执行日志记录。
但我想做如下的事情:
public void login(User user) {
String userType = user.getType();
if (!user.isActive()) {
// point cut 1 -- log inactive user
} else if (!user.isPasswordValid()) {
// point cut 2 -- log wrong password
} else {
// point cut 3 -- log successful login
}
}
我们有既定的日志格式。像这样的东西:
<actor>|<action_code>|<error_code>|<extra_info>
所有 Actor 类型、操作和错误代码都包含在枚举中。
有没有办法告诉 AspectJ:
在“ifs”内登录,并且根据发生的情况记录不同的信息?例如,在切入点 1 中记录以下内容之一:
admin|login|001|Admin user inactive
user|login|001|Normal user inactive
...并在切入点 2 中记录以下内容之一:
admin|login|002|Invalid Admin password
user|login|002|Invalid normal user password
...并在切入点 3 中记录以下内容之一:
admin|login|000|Successful Admin login
user|login|000|Successful Normal user login
有件事告诉我这是不可能的。或者至少不容易。但我不确定这是否值得尝试。所以我很伤心。一方面,我想“清理”所有日志记录的代码。另一方面,我不确定实现这个是否会需要太多工作。
有什么想法吗?
******************************************** 编辑********************************************
谢谢两位的回答!我现在意识到两件事: 1. 我还有很多工作要做。 2.我认为我过于强调“登录”示例。
登录只是一个微小的用例。我的任务是在任何地方添加日志记录......在许多很多类的一堆方法中。基本上在应用程序中的任何地方我都会看到 LOG.debug() 或 LOG.info(),以将其替换为方面日志记录。这也意味着,尽管我愿意,但我不能仅仅重构所有代码来让我的生活更轻松。我想让登录使用异常,但这超出了我的任务范围:添加日志记录。
当然,在每种方法中,业务逻辑都会不同,因此日志记录也会不同。所以我的问题是:执行此操作的最佳实践是什么?我的意思是,每个方法都有自己的逻辑,它的 ifs ...并且会有条件地记录不同的内容。那么我是否应该继续为这些用例中的每一个创建一个切面类,并且基本上也有相同的“ifs”?
示例(不是登录!):导入数据的方法。
public void import(String type) {
if (type.equals("people")) {
try {
int result = importPeople();
if (result > 0) {
// do some stuff
LOG.info("ok");
} else {
// do some stuff
LOG.info("problem");
}
} catch (Exception e) {
// do some stuff
LOG.debug("exception ...");
}
} else if (type.equals("places")) {
try {
int result = importPlaces();
if (result > 0) {
// do some stuff
LOG.info("ok");
} else {
// do some stuff
LOG.info("problem");
}
} catch (Exception e) {
// do some stuff
LOG.debug("exception ...");
}
}
}
请注意,这是一个糟糕的示例,包含重复的代码等。但您明白了。我是否还应该创建一个“导入”方面,用于记录此方法......以及所有随附的“ifs”来记录“ok”,“问题”,“异常”?并为每个用例执行此操作?
我完全赞成摆脱侵入式日志记录代码,但是......这似乎有点代码味道,必须在原始方法(因为该方法比日志记录“做更多的事情”)以及相应的方面中都必须具有逻辑,及其“ifs”等......
无论如何,你们都回答了我最初的问题...但我只能有 1 个答案,所以我将接受 kriegaex 的答案,因为他似乎投入了很多工作!
最佳答案
是的,这是可能的。但如果我是你,我会对整个故事进行稍微不同的建模。首先,我会抛出由于未知或不活动用户或错误密码而导致登录失败的异常。或者,登录方法可以返回一个 boolean 值(成功登录则返回 true,否则返回 false)。但在我看来,这更像是老式的 C 风格,而不是现代的 OOP。
这是一个自洽的例子。对于带有大量静态成员和方法的丑陋的 UserDB
类,我们深表歉意。实际上,您不会存储明文密码,而是存储随机盐和加盐哈希值。但毕竟它只是基于方面的条件日志记录的概念证明。
用于登录的用户 bean:
package de.scrum_master.app;
public class User {
private String id;
private String password;
public User(String id, String password) {
this.id = id;
this.password = password;
}
public String getId() {
return id;
}
public String getPassword() {
return password;
}
}
用户数据库:
为了简单起见,有硬编码的数据库条目、静态枚举、成员和方法以及静态内部类。对不起!我希望您可以轻松想象如何通过更好的设计来做到这一点。
package de.scrum_master.app;
import java.util.HashMap;
import java.util.Map;
public class UserDB {
public static enum Role { admin, user, guest }
public static enum Action { login, logout, read, write }
public static enum Error { successful_login, user_inactive, invalid_password, unknown_user }
private static class UserInfo {
String password;
Role role;
boolean active;
public UserInfo(String password, Role role, boolean active) {
this.password = password;
this.role = role;
this.active = active;
}
}
private static Map<String, UserInfo> knownUsers = new HashMap<>();
static {
knownUsers.put("bruce", new UserInfo("alm1GHTy", Role.admin, true));
knownUsers.put("john", new UserInfo("LetMe_in", Role.user, true));
knownUsers.put("jane", new UserInfo("heLL0123", Role.guest, true));
knownUsers.put("richard", new UserInfo("dicky", Role.user, false));
knownUsers.put("martha", new UserInfo("paZZword", Role.admin, false));
}
public static class UserDBException extends Exception {
private static final long serialVersionUID = 7662809670014934460L;
public final String userId;
public final Role role;
public final Action action;
public final Error error;
public UserDBException(String userId, Role role, Action action, Error error, String message) {
super(message);
this.userId = userId;
this.role = role;
this.action = action;
this.error = error;
}
}
public static boolean isKnown(User user) {
return knownUsers.get(user.getId()) != null;
}
public static boolean isActive(User user) {
return isKnown(user) && knownUsers.get(user.getId()).active;
}
public static boolean isPasswordValid(User user) {
return isKnown(user) && knownUsers.get(user.getId()).password.equals(user.getPassword());
}
public static Role getRole(User user) {
return isKnown(user) ? knownUsers.get(user.getId()).role : null;
}
public static void login(User user) throws UserDBException {
String userId = user.getId();
if (!isKnown(user))
throw new UserDBException(
userId, getRole(user), Action.login,
Error.unknown_user, "Unknown user"
);
if (!isActive(user))
throw new UserDBException(
userId, getRole(user), Action.login,
Error.user_inactive, "Inactive " + getRole(user)
);
if (!isPasswordValid(user))
throw new UserDBException(
userId, getRole(user), Action.login,
Error.invalid_password, "Invalid " + getRole(user) + " password"
);
}
}
请注意 login(User)
方法如何抛出异常,并提供有助于日志记录的详细信息。
驱动程序应用程序模拟多个用户/密码组合的登录:
package de.scrum_master.app;
import java.util.Arrays;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("mr_x", "foobar"),
new User("bruce", "foobar"),
new User("bruce", "alm1GHTy"),
new User("john", "foobar"),
new User("john", "LetMe_in"),
new User("jane", "foobar"),
new User("jane", "heLL0123"),
new User("richard", "foobar"),
new User("richard", "dicky"),
new User("martha", "foobar"),
new User("martha", "paZZword")
);
for (User user : users) {
try {
UserDB.login(user);
System.out.printf("%-8s -> %s%n", user.getId(), "Successful " + UserDB.getRole(user) + " login");
} catch (Exception e) {
System.out.printf("%-8s -> %s%n", user.getId(), e.getMessage());
}
}
}
}
请注意,我们只是捕获并记录所有异常,以避免应用程序在登录尝试失败后退出。
控制台日志:
mr_x -> Unknown user
bruce -> Invalid admin password
bruce -> Successful admin login
john -> Invalid user password
john -> Successful user login
jane -> Invalid guest password
jane -> Successful guest login
richard -> Inactive user
richard -> Inactive user
martha -> Inactive admin
martha -> Inactive admin
登录记录器方面:
我建议您首先注释掉 Application.main(..)
中的两个 System.out.printf(..)
调用,以免将它们与方面日志记录混淆。
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import de.scrum_master.app.User;
import de.scrum_master.app.UserDB;
import de.scrum_master.app.UserDB.Action;
import de.scrum_master.app.UserDB.Error;
import de.scrum_master.app.UserDB.UserDBException;
@Aspect
public class UserActionLogger {
@Around("execution(void de.scrum_master.app.UserDB.login(*)) && args(user)")
public void captureLogin(ProceedingJoinPoint thisJoinPoint, User user) throws Throwable {
try {
thisJoinPoint.proceed();
System.out.printf("%s|%s|%d03|%s%n",
user.getId(), Action.login, Error.successful_login.ordinal(),
"Successful " + UserDB.getRole(user) + " login"
);
} catch (UserDBException e) {
System.out.printf("%s|%s|%03d|%s%n",
e.userId, e.action, e.error.ordinal(),
e.getMessage()
);
throw e;
}
}
}
方面的控制台日志:
mr_x|login|003|Unknown user
bruce|login|002|Invalid admin password
bruce|login|003|Successful admin login
john|login|002|Invalid user password
john|login|003|Successful user login
jane|login|002|Invalid guest password
jane|login|003|Successful guest login
richard|login|001|Inactive user
richard|login|001|Inactive user
martha|login|001|Inactive admin
martha|login|001|Inactive admin
瞧!我希望这大致就是您想要的。
关于java - 如何使用 AspectJ 有条件地记录不同的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39531538/
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!