如何在 JSF 2 中创建自定义转换器?
我有一个名为“操作”的实体:
@Entity
@Table(name="operation")
public class Operation implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Integer id;
@NotNull(message="informe um tipo de operação")
private String operation;
//bi-directional many-to-one association to Product
@OneToMany(mappedBy="operation")
private List<Product> products;
// getter and setters
}
我以这种方式检索操作:(它可以通过 EJB 实例,但只是为了将其保留在本地并作为示例,好吗?;))
public Map<String, Object> getOperations() {
operations = new LinkedHashMap<String, Object>();
operations.put("Select an operation", new Operation());
operations.put("Donation", new Operation(new Integer(1), "donation"));
operations.put("Exchange", new Operation(new Integer(2), "exchange"));
return operations;
}
所以我试图获取所选操作在此 selectOneMenu
中:
productc
是一个具有 viewScope
的 ManagedBean
,productb
是一个具有 sessionScope
的 ManagedBean code> 其中有一个 product
这是我的实体。产品包含一个操作
,所以是这样的:(
字母c有控制的意思,所有与我的实体产品相关的操作都应该由这个bean来处理,好吗?)
Product productc (ViewScope)
-- ProductBean productb (SessionScope)
---- Product product (Entity)
-------- Operation operation (Entity)
转换器与@BalusC之前建议的相同:
@ManagedBean
@RequestScoped
public class OperationConverter implements Converter {
@EJB
private EaoOperation operationService;
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Operation) || ((Operation) value).getId() == null) {
return null;
}
return String.valueOf(((Operation) value).getId());
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
Operation operation = operationService.find(Integer.valueOf(value));
System.out.println("Getting the operation value = " + operation.getOperation() );
if (operation == null) {
throw new ConverterException(new FacesMessage("Unknown operation ID: " + value));
}
return operation;
}
哪个检索日志中显示的所选操作:
FINE: SELECT ID, OPERATION FROM operation WHERE (ID = ?)
bind => [1 parameter bound]
INFO: Getting the operation value = exchange
所以当我尝试提交表单时出现以下错误:
form_add_product:operation: Validation error: the value is not valid
为什么会发生这种情况?
I have this Entity called 'Operation':
@Entity
@Table(name="operation")
public class Operation implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Integer id;
@NotNull(message="informe um tipo de operação")
private String operation;
//bi-directional many-to-one association to Product
@OneToMany(mappedBy="operation")
private List<Product> products;
// getter and setters
}
I retrieve the operations this way: (It could be through an EJB instance but just to keep it local and as an example, okay? ;) )
public Map<String, Object> getOperations() {
operations = new LinkedHashMap<String, Object>();
operations.put("Select an operation", new Operation());
operations.put("Donation", new Operation(new Integer(1), "donation"));
operations.put("Exchange", new Operation(new Integer(2), "exchange"));
return operations;
}
So I'm trying to get the selected operation in this selectOneMenu
:
The productc
is a ManagedBean
which has a viewScope
, productb
is a ManagedBean with a sessionScope
which has a product
which is my entity. The product contais one operation
, so is something like this:
(the letter c has the meaning of control, where all operations related about my entity product should be handled by this bean, okay?)
Product productc (ViewScope)
-- ProductBean productb (SessionScope)
---- Product product (Entity)
-------- Operation operation (Entity)
The converter is the same as @BalusC is suggest before:
@ManagedBean
@RequestScoped
public class OperationConverter implements Converter {
@EJB
private EaoOperation operationService;
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (!(value instanceof Operation) || ((Operation) value).getId() == null) {
return null;
}
return String.valueOf(((Operation) value).getId());
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
Operation operation = operationService.find(Integer.valueOf(value));
System.out.println("Getting the operation value = " + operation.getOperation() );
if (operation == null) {
throw new ConverterException(new FacesMessage("Unknown operation ID: " + value));
}
return operation;
}
Which retrieve the operation selected as showed in the log:
FINE: SELECT ID, OPERATION FROM operation WHERE (ID = ?)
bind => [1 parameter bound]
INFO: Getting the operation value = exchange
So when I try to submit the form gives the follow error:
form_add_product:operation: Validation error: the value is not valid
Why is this happening?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正在尝试将一个复杂的对象作为 HTTP 请求参数传递,该参数只能是
String
。 JSF/EL 具有用于原语及其包装器(例如int
、Integer
)甚至枚举的内置转换器。但对于所有其他类型,您确实需要编写一个自定义转换器。在这种情况下,您需要编写一个在String
和Operation
之间进行转换的转换器。然后将String
用作选项值(在浏览器中打开页面,右键单击并查看源代码并注意<选项值>
)。然后将Operation
用作模型值。String
应唯一标识Operation
对象。您可以为此使用操作 ID。但在这种特殊情况下,有了这样的硬编码映射和相对简单的模型,我认为使用
enum
更容易。但
。
如果这些值实际上要从数据库中检索,并且其大小未定义,那么您仍然需要一个自定义转换器 您可以在
getAsString()
中返回 ID,并在getAsObject()
中使用操作 DAO/EJB 通过 ID 获取Operation
。使用方式如下:
至于为什么它是
@ManagedBean
而不是@FacesConverter
,请阅读以下内容:转换并验证 GET 请求参数。更新关于
验证错误:值无效
错误,这意味着Operation
的equals()
方法> 类损坏或丢失。在验证期间,JSF 通过Object#equals()
将提交的值与可用值列表进行比较。如果列表中没有一个与提交的值匹配,那么您将看到此错误。因此,请确保equals()
正确实现。这是一个通过数据库技术特性进行比较的基本示例。不要忘记同时实现
hashCode()
:You're trying to pass a complex object around as HTTP request parameter which can be only be a
String
. JSF/EL has builtin converters for primitives and its wrappers (e.g.int
,Integer
) and even enums. But for all other types you really need to write a custom converter. In this case you need to write a converter which converts betweenString
andOperation
. TheString
is then used as option value (open page in browser, rightclick and View Source and notice the<option value>
). TheOperation
is then used as model value. TheString
should uniquely identify theOperation
object. You could use operation ID for this.But in this particular case, with such a hardcoded map and a relatively simple model, I think it's easier to use an
enum
instead.with
and
But if those values have actually to be retrieved from the DB and its size is undefinied, then you still really need a custom converter. You could in
getAsString()
return the ID and ingetAsObject()
use the operation DAO/EJB to get anOperation
by the ID.Use it as follows:
As to why it's a
@ManagedBean
instead of@FacesConverter
, read this: Converting and validating GET request parameters.Update as to the
Validation Error: value not valid
error, this means that theequals()
method of theOperation
class is broken or missing. During validation, JSF compares the submitted value with the list of available values byObject#equals()
. If no one of the list matches with the submitted value, then you'll see this error. So, ensure thatequals()
is properly implemented. Here's a basic example which compares by the DB technical identity.Don't forget to implement
hashCode()
as well: