作为
correct Answer by Schild
说,你必须
override your
equals
and
hashCode
对于数据驱动的业务对象,这通常意味着只需查看对象上的标识符,该标识符是您在数据库中的主键(如果您使用数据库,则会是主键)。
如下例所示,我们的
Status
类有一个
UUID
universally unique identifier (UUID)
(128位值,规范地显示为36个字符的十六进制字符串,带有连字符)。我们的
等于
和
哈希码
只考虑对象的一个成员。
@Override
public boolean equals ( Object obj ) { // Compare the UUID member named `uuid`.
if ( obj == this ) { return true; }
if ( obj instanceof Status ) { return this.getUuid().equals( ( ( Status ) obj ).getUuid() ); }
return false;
}
@Override
public int hashCode () {
return Objects.hashCode( this.uuid );
} // Compare the UUID member named `uuid`.
示例应用程序
在本例中,我们跟踪三个设备。一个
地位
对象表示每个对象。
NativeSelect
在Vaadin中),并单击某个按钮。在这里选择行是不相关的。
为了您的启发,我在
Grid
. 这两种方法在Vaadin业务应用程序中都很常见:
-
修改现有
对象支持
网格
-
替换目标
对象,但在其id字段中使用相同的标识符值。
例如,在某些情况下,可以编写数据存储库服务代码以始终返回新实例。在其他情况下,我们可能有意地用改变来更新现有对象。
private void updateByModifying ( Status s , Integer integer ) {
s.setCurrentStatus( integer );
grid.getDataProvider().refreshItem( s );
}
private void updateByInstantiating ( Status s , Integer integer ) {
boolean removed = statuses.remove( s );
Status replacement = new Status( s.getUuid() , s.getName() , integer );
boolean added = statuses.add( replacement );
grid.getDataProvider().refreshItem( replacement );
}
在本演示中,使用
Update row by
弹出式菜单(也称为下拉列表)。这两种方法都是通过调用
DataProvider::refreshItem
. 注意,这两种方法都依赖于
等于
哈希码
正在正确实施。
Refresh all
显示使用的按钮
DataProvider::refreshAll
方法。
源代码
-
MyUI.java
(进入瓦丁)
-
Status.java
(我们的业务对象,POJO)
-
StatusLayout
MyUI.java
package com.basilbourque.example;
import javax.servlet.annotation.WebServlet;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.*;
import java.util.List;
import java.util.UUID;
/**
* This UI is the application entry point. A UI may either represent a browser window
* (or tab) or some part of an HTML page where a Vaadin application is embedded.
* <p>
* The UI is initialized using {@link #init(VaadinRequest)}. This method is intended to be
* overridden to add component to the user interface and initialize non-component functionality.
*/
@Theme ( "mytheme" )
public class MyUI extends UI {
@Override
protected void init ( VaadinRequest vaadinRequest ) {
Layout layout = new StatusLayout();
this.setContent( layout );
}
@WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
@VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
public static class MyUIServlet extends VaadinServlet {
}
}
Status.java状态
package com.basilbourque.example;
import java.util.Objects;
import java.util.UUID;
public class Status {
// Members.
private UUID uuid;
private String name;
private Integer currentStatus; // 1 = Good, 0 = okay, -1 = Bad.
// Constructor.
public Status ( UUID uuid , String name , Integer currentStatus ) {
this.uuid = uuid;
this.name = name;
this.currentStatus = currentStatus;
}
// -----------| Object |-------------------------
@Override
public boolean equals ( Object obj ) { // Compare the UUID member named `uuid`.
if ( obj == this ) { return true; }
if ( obj instanceof Status ) { return this.getUuid().equals( ( ( Status ) obj ).getUuid() ); }
return false;
}
@Override
public int hashCode () {
return Objects.hashCode( this.uuid );
} // Compare the UUID member named `uuid`.
@Override
public String toString () {
return "Status{ " +
"uuid=" + uuid +
" | name='" + name + '\'' +
" | currentStatus=" + currentStatus +
" }";
}
// -----------| Accessors |-----------------------------
public UUID getUuid () {
return uuid;
}
public void setUuid ( UUID uuid ) {
this.uuid = uuid;
}
public String getName () {
return name;
}
public void setName ( String name ) { this.name = name; }
public Integer getCurrentStatus () {
return currentStatus;
}
public void setCurrentStatus ( Integer currentStatus ) {
this.currentStatus = currentStatus;
}
}
StatusLayout.java状态布局
package com.basilbourque.example;
import com.vaadin.data.provider.ListDataProvider;
import com.vaadin.ui.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public class StatusLayout extends VerticalLayout {
// Members
List< Status > statuses;
Grid< Status > grid;
final List< Integer > numbers = List.of( 1 , 0 , - 1 );
NativeSelect< Integer > numberPopup;
NativeSelect< Boolean > updatyByModifyingOrInstantiating;
Button setPump, setCamera, setSensor, refreshAllButton;
// Constructor
public StatusLayout () {
statuses = new ArrayList<>( 3 );
statuses.add( new Status( UUID.fromString( "1c0d183e-c2ba-11e8-a355-529269fb1459" ) , "Pump" , numbers.get( 0 ) ) );
statuses.add( new Status( UUID.fromString( "2490c74e-1aac-4d71-9a2c-880628dcfc28" ) , "Camera" , numbers.get( 1 ) ) );
statuses.add( new Status( UUID.fromString( "6ae07414-f557-4a1e-a552-cb5ec5f48476" ) , "Sensor" , numbers.get( 2 ) ) );
// Create a grid bound to the list
grid = new Grid<>( Status.class );
grid.setCaption( "Equipment Status" );
grid.setItems( statuses );
// grid.addColumn( Status :: getName ).setCaption( "Name" );
// grid.addColumn( Status :: getCurrentStatus ).setCaption( "Status" );
updatyByModifyingOrInstantiating = new NativeSelect<>( "Update row by: " , List.of( Boolean.TRUE , Boolean.FALSE ) );
updatyByModifyingOrInstantiating.setValue( Boolean.TRUE );
updatyByModifyingOrInstantiating.setItemCaptionGenerator( ( ItemCaptionGenerator< Boolean > ) item -> item ? "modifying" : "instantiating" );
Label valueSetterLabel = new Label( "Set status:" );
numberPopup = new NativeSelect<>();
numberPopup.setItems( numbers );
numberPopup.setValue( numbers.get( 1 ) );
// numberPopup.setItemCaptionGenerator( item -> List.of( "Good" , "Okay" , "Bad" ).get( numbers.indexOf( item ) ) ); // Display words rather than the underlying number.
// The `buttonClick` method below has logic depending on match between button name and `name` property on `Status` objects in grid.
setPump = new Button( statuses.get( 0 ).getName() ); // Pump
setPump.addClickListener( this :: buttonClick );
setCamera = new Button( statuses.get( 1 ).getName() ); // Camera
setCamera.addClickListener( this :: buttonClick );
setSensor = new Button( statuses.get( 2 ).getName() ); // Sensor
setSensor.addClickListener( this :: buttonClick );
refreshAllButton = new Button( "Refresh all" );
refreshAllButton.addClickListener( clickEvent -> grid.getDataProvider().refreshAll() );
// Arrange
grid.setWidth( 100 , Unit.PERCENTAGE );
HorizontalLayout valueSetterBar = new HorizontalLayout();
valueSetterBar.addComponents( valueSetterLabel , numberPopup , setPump , setCamera , setSensor );
valueSetterBar.setComponentAlignment( valueSetterLabel , Alignment.MIDDLE_CENTER );
valueSetterBar.setComponentAlignment( numberPopup , Alignment.MIDDLE_CENTER );
valueSetterBar.setComponentAlignment( setPump , Alignment.MIDDLE_CENTER );
valueSetterBar.setComponentAlignment( setCamera , Alignment.MIDDLE_CENTER );
valueSetterBar.setComponentAlignment( setSensor , Alignment.MIDDLE_CENTER );
addComponents( grid , updatyByModifyingOrInstantiating , valueSetterBar , refreshAllButton );
}
private void buttonClick ( Button.ClickEvent clickEvent ) {
System.out.println( "TRACE - Setting " + clickEvent.getButton().getCaption() + " to " + this.numberPopup.getValue().toString() );
// Find the `Status` object in the `List` whose name matches the name of the button clicked by user.
Optional< Status > optionalStatus = statuses.stream().filter( status -> status.getName().equals( clickEvent.getButton().getCaption() ) ).findFirst();
// We expect the matching `Status` to always be found. If not, throw exception.
Status s = optionalStatus.orElseThrow( () -> new IllegalStateException( "Failed to find expected item in list of statuses: " + clickEvent.getButton().getCaption() ) );
Integer valueToSet = this.numberPopup.getValue();
// Set the `currentStatus` property on the `Status` object to the value of the selected popup menu item.
// Try either updating by modifying existing row or by instantiating a new one.
// Comment-out either of the next two lines.
if(updatyByModifyingOrInstantiating.getValue().equals( Boolean.TRUE )) {
this.updateByModifying( s , valueToSet );
} else {
this.updateByInstantiating( s , valueToSet );
}
}
private void updateByModifying ( Status s , Integer integer ) {
s.setCurrentStatus( integer );
grid.getDataProvider().refreshItem( s );
}
private void updateByInstantiating ( Status s , Integer integer ) {
boolean removed = statuses.remove( s );
Status replacement = new Status( s.getUuid() , s.getName() , integer );
boolean added = statuses.add( replacement );
grid.getDataProvider().refreshItem( replacement );
}
}