我正在用Java编写Web服务,我试图找出定义错误代码及其相关错误字符串的最佳方法。我需要将数字错误代码和错误字符串组合在一起。错误代码和错误字符串都将发送到访问Web服务的客户端。例如,当发生SQLException时,我可能想要执行以下操作:
// Example: errorCode = 1,
// errorString = "There was a problem accessing the database."
throw new SomeWebServiceException(errorCode, errorString);
客户端程序可能会显示消息:
“错误#1已经发生:有一个 访问数据库的问题。“
我的第一个想法是使用Enum
错误代码并覆盖toString
方法以返回错误字符串。以下是我提出的建议:
public enum Errors {
DATABASE {
@Override
public String toString() {
return "A database error has occured.";
}
},
DUPLICATE_USER {
@Override
public String toString() {
return "This user already exists.";
}
},
// more errors follow
}
我的问题是:有更好的方法吗?我更喜欢代码中的解决方案,而不是从外部文件读取。我在这个项目中使用Javadoc,并且能够在线记录错误代码并在文档中自动更新它们会有所帮助。
答案 0 :(得分:147)
当然,enum解决方案肯定会有更好的实现(通常非常好):
public enum Error {
DATABASE(0, "A database error has occured."),
DUPLICATE_USER(1, "This user already exists.");
private final int code;
private final String description;
private Error(int code, String description) {
this.code = code;
this.description = description;
}
public String getDescription() {
return description;
}
public int getCode() {
return code;
}
@Override
public String toString() {
return code + ": " + description;
}
}
您可能希望覆盖toString()以仅返回描述 - 不确定。无论如何,重点是您不需要为每个错误代码单独覆盖。另请注意,我已明确指定代码而不是使用序数值 - 这样可以更轻松地更改顺序并在以后添加/删除错误。
不要忘记,这根本不是国际化的 - 但除非您的Web服务客户端向您发送区域设置描述,否则无论如何都无法轻易地将其国际化。至少他们会在客户端使用错误代码用于i18n ......
答案 1 :(得分:33)
就我而言,我更喜欢将属性文件中的错误消息外部化。 这对于应用程序的国际化(每种语言一个属性文件)非常有用。修改错误消息也更容易,并且不需要重新编译Java源代码。
在我的项目中,通常我有一个包含错误代码的接口(字符串或整数,它并不关心),其中包含此错误的属性文件中的键:
public interface ErrorCodes {
String DATABASE_ERROR = "DATABASE_ERROR";
String DUPLICATE_USER = "DUPLICATE_USER";
...
}
在属性文件中:
DATABASE_ERROR=An error occurred in the database.
DUPLICATE_USER=The user already exists.
...
您的解决方案的另一个问题是可维护性:您只有2个错误,并且已经有12行代码。 想象一下,当你需要管理数百个错误时,你的Enumeration文件就会出现!
答案 2 :(得分:20)
重载toString()似乎有点icky - 这似乎是toString()正常使用的一小部分。
怎么样:
public enum Errors {
DATABASE(1, "A database error has occured."),
DUPLICATE_USER(5007, "This user already exists.");
//... add more cases here ...
private final int id;
private final String message;
Errors(int id, String message) {
this.id = id;
this.message = message;
}
public int getId() { return id; }
public String getMessage() { return message; }
}
对我来说似乎更清洁......而且不那么冗长。
答案 3 :(得分:16)
在我的上一份工作中,我在enum版本中更深入了一些:
public enum Messages {
@Error
@Text("You can''t put a {0} in a {1}")
XYZ00001_CONTAINMENT_NOT_ALLOWED,
...
}
@ Error,@ Info,@ Warning保留在类文件中,并且在运行时可用。 (我们还有一些其他注释来帮助描述消息传递)
@Text是一个编译时注释。
我为此编写了一个注释处理器,它执行了以下操作:
我编写了一些实用程序例程来帮助记录错误,将它们包装为异常(如果需要)等等。
我想让他们让我开源...... - 斯科特
答案 4 :(得分:5)
我建议你看一下java.util.ResourceBundle。你应该关心I18N,但即使你不这样做也是值得的。外化消息是一个非常好的主意。我发现能够向业务人员提供电子表格是很有用的,这些人员可以使用他们希望看到的确切语言。我们编写了一个Ant任务来在编译时生成.properties文件。它使I18N变得微不足道。
如果你也使用Spring,那就更好了。他们的MessageSource类对这些事情非常有用。
答案 5 :(得分:4)
只是为了继续鞭打这个特殊的死马 - 当向最终客户展示错误时,我们已经很好地利用了 数字错误代码 ,因为他们经常忘记或误读了实际的错误信息,但有时可能会保留并报告一个数字值,可以为您提供实际发生的事情的线索。
答案 6 :(得分:1)
我(以及我公司的其他团队)更愿意提出异常而不是返回错误代码。错误代码必须在任何地方进行检查,传递,并且当代码量变大时,往往会使代码无法读取。
然后错误类将定义消息。
PS:实际上也关心国际化!答案 7 :(得分:1)
有点晚了但是,我只是在为自己寻找一个漂亮的解决方案。如果您有不同类型的消息错误,您可以添加简单的自定义消息工厂,以便您可以指定更多您想要的详细信息和格式。
public enum Error {
DATABASE(0, "A database error has occured. "),
DUPLICATE_USER(1, "User already exists. ");
....
private String description = "";
public Error changeDescription(String description) {
this.description = description;
return this;
}
....
}
Error genericError = Error.DATABASE;
Error specific = Error.DUPLICATE_USER.changeDescription("(Call Admin)");
编辑: 好吧,因为你永久改变特定的枚举,所以在这里使用枚举是有点危险的。 我想更好的是更改为类并使用静态字段,但是你不能再使用'=='了。所以我想这是一个很好的例子,不做什么,(或者只在初始化期间做):)
答案 8 :(得分:1)
有很多方法可以解决这个问题。我首选的方法是使用接口:
public interface ICode {
/*your preferred code type here, can be int or string or whatever*/ id();
}
public interface IMessage {
ICode code();
}
现在您可以定义任意数量的提供消息的枚举:
public enum DatabaseMessage implements IMessage {
CONNECTION_FAILURE(DatabaseCode.CONNECTION_FAILURE, ...);
}
现在您可以选择将其转换为字符串。您可以将字符串编译到代码中(使用注释或枚举构造函数参数),也可以从配置/属性文件或数据库表或混合中读取它们。后者是我首选的方法,因为你总是需要一些消息,你可以很早就把它们变成文本(例如,而你连接到数据库或阅读配置)。
我使用单元测试和反射框架来查找实现我的接口的所有类型,以确保每个代码都在某处使用,并且配置文件包含所有预期的消息等。
使用可以解析Java https://github.com/javaparser/javaparser或the one from Eclipse等Java的框架,您甚至可以检查枚举的使用位置并查找未使用的枚举。
答案 9 :(得分:0)
错误代码/消息定义的枚举仍然是一个很好的解决方案,尽管它有一个i18n问题。实际上我们可能有两种情况:代码/消息显示给最终用户或系统集成商。对于后一种情况,I18N不是必需的。我认为Web服务很可能是后一种情况。
答案 10 :(得分:0)
使用interface
作为消息常量通常是一个坏主意。它将作为导出API的一部分永久泄漏到客户端程序中。谁知道,后来的客户端程序员可能会将错误消息(公共)解析为其程序的一部分。
您将永久锁定以支持此功能,因为字符串格式的更改将/可能会破坏客户端程序。
答案 11 :(得分:0)
请按照以下示例:
public enum ErrorCodes {
NO_File("No file found. "),
private ErrorCodes(String value) {
this.errordesc = value;
}
private String errordesc = "";
public String errordesc() {
return errordesc;
}
public void setValue(String errordesc) {
this.errordesc = errordesc;
}
};
在你的代码中调用它:
fileResponse.setErrorCode(ErrorCodes.NO_FILE.errordesc());
答案 12 :(得分:0)
我使用PropertyResourceBundle在企业应用程序中定义错误代码,以管理区域设置错误代码资源。当错误代码的数量庞大且结构化时,这是处理错误代码的最佳方法,而不是编写代码(对于少数错误代码来说可能很合适)。
请参阅Java文档以获取有关PropertyResourceBundle的更多信息