PlayFramework 2.5 - 使用反射更新 Ebean
PlayFramework 2.5 - Ebean update using reflection
我正在使用 Play framework 2.5 和 Ebean 作为 ORM 开发一个带有内联编辑器的网站,我有一个新闻部分,管理员可以在其中编辑每条新闻(编辑内联字段,如标题、内容等)。
为此,我将每个可以用等于新闻模型字段的 id 修改的 html 元素设置为(例如,映射字段标题的 html 元素将具有 id="title" ), 然后当我从客户端接收数据时,我在控制器上使用反射将每个内容映射到正确的新闻字段。
这是代码(EditContent 是一个 object,其中包含每个修改内容的 ID 和 htmlContent 等信息):
News news = News.find.byId(newsId);
for(EditContent content : pageContents.contents) {
Field field = news.getClass().getField(content.cssId);
field.setAccessible(true);
field.set(news, content.htmlContent);
}
news.update();
问题是似乎执行了更新,但实际上并没有在数据库上更新值。使用调试器,我检查了 object 新闻,我可以看到字段已正确修改,但更新对数据库没有影响。
另外,我注意到相同的代码使用:
News news = new News()
...
//reflection to save modifed contents in the new object
...
news.save()
如我所料,在数据库中保存了一个新行。
有什么想法吗?
提前感谢您的帮助!
您正在设置字段值,而不是调用 setter 方法。
因此对于 update() ... Ebean 不知道哪些属性已更改 - 它认为 none 已更改。
Play 通过增强将字段 put 调用修改为方法调用。所以这可能就是您认为这些反射场设置值可能有效的原因。
所以基本上,正如@Rob Bygrave 所说...应该在此处调用 setter 方法而不是直接设置字段值,因为如果将值设置为相应的值,ebean 将忽略新值直接打野。 play framework 似乎遵循了Java bean 约定,所以基本上我们可以猜到set name 叫什么。
这是动态更新用户信息的示例代码:
private final String[] userUpdatableNames = { "name", "password", "allowGPS" };
...
JsonNode dateForm = request().body().asJson();
Field field;
Class<?> type;
Method method;
for (int i = 0; i < userUpdatableNames.length; i++) {
if (isArgs[i]) {
try {
field = target.getClass().getDeclaredField(userUpdatableNames[i]);
type = field.getType();
Method method = target.getClass().getMethod("set" + initialUpperize(userUpdatableNames[i]), type);
method.invoke(target, convert(type,dateForm.findValue(userUpdatableNames[i]).textValue()));
}catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException
| NoSuchMethodException | InvocationTargetException e) {
return internalServerError(Json.toJson("Invoke exception"));
}
}
}
...
public String initialUpperize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
...
private Object convert(Class<?> targetType, String text) {
PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
editor.setAsText(text);
return editor.getValue();
}
其中isArgs是一个布尔数组,用于标记该字段是否在Json正文中...
谢谢
我正在使用 Play framework 2.5 和 Ebean 作为 ORM 开发一个带有内联编辑器的网站,我有一个新闻部分,管理员可以在其中编辑每条新闻(编辑内联字段,如标题、内容等)。
为此,我将每个可以用等于新闻模型字段的 id 修改的 html 元素设置为(例如,映射字段标题的 html 元素将具有 id="title" ), 然后当我从客户端接收数据时,我在控制器上使用反射将每个内容映射到正确的新闻字段。
这是代码(EditContent 是一个 object,其中包含每个修改内容的 ID 和 htmlContent 等信息):
News news = News.find.byId(newsId);
for(EditContent content : pageContents.contents) {
Field field = news.getClass().getField(content.cssId);
field.setAccessible(true);
field.set(news, content.htmlContent);
}
news.update();
问题是似乎执行了更新,但实际上并没有在数据库上更新值。使用调试器,我检查了 object 新闻,我可以看到字段已正确修改,但更新对数据库没有影响。
另外,我注意到相同的代码使用:
News news = new News()
...
//reflection to save modifed contents in the new object
...
news.save()
如我所料,在数据库中保存了一个新行。
有什么想法吗?
提前感谢您的帮助!
您正在设置字段值,而不是调用 setter 方法。
因此对于 update() ... Ebean 不知道哪些属性已更改 - 它认为 none 已更改。
Play 通过增强将字段 put 调用修改为方法调用。所以这可能就是您认为这些反射场设置值可能有效的原因。
所以基本上,正如@Rob Bygrave 所说...应该在此处调用 setter 方法而不是直接设置字段值,因为如果将值设置为相应的值,ebean 将忽略新值直接打野。 play framework 似乎遵循了Java bean 约定,所以基本上我们可以猜到set name 叫什么。 这是动态更新用户信息的示例代码:
private final String[] userUpdatableNames = { "name", "password", "allowGPS" };
...
JsonNode dateForm = request().body().asJson();
Field field;
Class<?> type;
Method method;
for (int i = 0; i < userUpdatableNames.length; i++) {
if (isArgs[i]) {
try {
field = target.getClass().getDeclaredField(userUpdatableNames[i]);
type = field.getType();
Method method = target.getClass().getMethod("set" + initialUpperize(userUpdatableNames[i]), type);
method.invoke(target, convert(type,dateForm.findValue(userUpdatableNames[i]).textValue()));
}catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException
| NoSuchMethodException | InvocationTargetException e) {
return internalServerError(Json.toJson("Invoke exception"));
}
}
}
...
public String initialUpperize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
...
private Object convert(Class<?> targetType, String text) {
PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
editor.setAsText(text);
return editor.getValue();
}
其中isArgs是一个布尔数组,用于标记该字段是否在Json正文中...
谢谢