Java:Play Framework - 如何使用Formatters绑定实体

时间:2016-11-01 22:28:28

标签: java playframework converter bind

我正在学习Play Framework,我需要从网络表单中将Address绑定到Person

有我的实体:

@Entity
@Table(name = "address")
public class Address {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;

    private String country;

    @OneToMany(mappedBy = "address", fetch = FetchType.EAGER)
    private List<Person> persons;

// get/set
}


@Entity
@Table(name = "person")
public class Person {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;

    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    private Address address;

    // get/set
}

我有以下控制器和dao:

public class HomeController extends Controller {

    @Inject
    private Configuration configuration;
    @Inject
    private PersonManager personManager;
    @Inject
    private AddressManager addressManager;
    @Inject
    FormFactory formFactory;
    @Inject
    Formatters formatters;

    @Transactional
    public Result index() {
        List<Person> persons = personManager.findAll();
        List<Address> addresses = addressManager.findAll();
        return ok(index.render("Hello, world", persons, addresses));
    }

    @Transactional
    public Result addPerson() {
        DynamicForm requestData = formFactory.form().bindFromRequest();
        System.out.println("form: " + requestData.get("address"));

        Person person = Form.form(Person.class).bindFromRequest().get();
        personManager.save(person);

        return redirect(routes.HomeController.index());
    }


    @Transactional
    public Result addAddress() {
        Address address = Form.form(Address.class).bindFromRequest().get();
        addressManager.save(address);
        return redirect(routes.HomeController.index());
    }
    // ...
}


package dao;

public class PersonDaoImpl implements PersonDao {

    @Inject
    private JPAApi jpaApi;

    @Override
    public void save(Person user) {
        jpaApi.em().persist(user);
    }

    @Override
    public void delete(Person user) {
        jpaApi.em().remove(user);
    }

    @Override
    public void update(Person user) {
        jpaApi.em().merge(user);
    }

    @Override
    public List<Person> findAll() {
        return jpaApi.em().createQuery("from Person").getResultList();
    }

    @Override
    public Person findById(int id) {
        return (Person) jpaApi.em().find(Person.class, id);
    }

    @Override
    public Person findByName(String name) {
        return (Person) jpaApi.em().createQuery("SELECT p FROM Person p WHERE p.name LIKE :name").setParameter("name", name).getSingleResult();
    }
}


package dao;

public class AddreessDaoImpl implements AddressDao {

    @Inject
    private JPAApi jpaApi;

    @Override
    public void save(Address address) {
        jpaApi.em().persist(address);
    }

    @Override
    public void delete(Address address) {
        jpaApi.em().remove(address);
    }

    @Override
    public void update(Address address) {
        jpaApi.em().merge(address);
    }

    @Override
    public List<Address> findAll() {
        return jpaApi.em().createQuery("from Address").getResultList();
    }

    @Override
    public Address findById(int id) {
        return (Address) jpaApi.em().find(Address.class, id);
    }

    @Override
    public Address findByCountry(String name) {
        return (Address) jpaApi.em().createQuery("SELECT a FROM Address a WHERE a.country LIKE :country").setParameter("country", name).getSingleResult();
    }
}

查看:

@(message: String, persons: List[Person], addresses: List[Address])

@main("Welcome to Play") {
        <form action="@routes.HomeController.addPerson()" method="post">
            <input type="text" name="name" />
            <select name="address">
                @for(address <- addresses) {
                    <option value="@address.getId">
                        @address.getCountry
                    </option>
                }
            </select>
            <button>Add Person</button>
        </form>
}

我需要添加具有现有地址的新人。我正在尝试使用Formatters

将地址绑定到人
package service;

import dao.AddressManager;
import models.Address;
import play.data.format.Formatters;
import play.i18n.MessagesApi;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.text.ParseException;
import java.util.Locale;

@Singleton
public class FormattersProvider implements Provider<Formatters> {

    private final MessagesApi messagesApi;

    @Inject
    public FormattersProvider(MessagesApi messagesApi) {
        this.messagesApi = messagesApi;
    }

    @Inject
    private AddressManager addressManager;

    @Override
    public Formatters get() {
        Formatters formatters = new Formatters(messagesApi);

        formatters.register(Address.class, new Formatters.SimpleFormatter<Address>(){
            @Override
            public Address parse(String input, Locale locale) throws ParseException {
                Address address = addressManager.findById(Integer.getInteger(input));
                return address;
            }

            @Override
            public String print(Address address, Locale locale) {
                return address.getCountry();
            }
        });

        return formatters;
    }
}


package service;

import com.google.inject.AbstractModule;
import play.data.format.Formatters;

public class FormattersModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Formatters.class).toProvider(FormattersProvider.class);
    }
}

但我怎么能使用Formatters?

如果我添加地址,那就没关系。

但是如果我使用db中的web表单地址列添加新的Person有NULL值,或者app崩溃:

[error] application - 

! @720fgnbfl - Internal server error, for (POST) [/person] ->

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[CompletionException: java.lang.IllegalStateException: Error(s) binding form: {"address":["Invalid value"]}]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:280)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:206)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
    at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.util.concurrent.CompletionException: java.lang.IllegalStateException: Error(s) binding form: {"address":["Invalid value"]}
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:593)
    at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577)
    at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
    at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1977)
    at scala.concurrent.java8.FuturesConvertersImpl$CF.apply(FutureConvertersImpl.scala:21)
    at scala.concurrent.java8.FuturesConvertersImpl$CF.apply(FutureConvertersImpl.scala:18)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
    at scala.concurrent.BatchingExecutor$Batch$$anonfun$run$1.processBatch$1(BatchingExecutor.scala:63)
Caused by: java.lang.IllegalStateException: Error(s) binding form: {"address":["Invalid value"]}
    at play.data.Form.get(Form.java:634)
    at controllers.HomeController.addPerson(HomeController.java:106)
    at router.Routes$$anonfun$routes$1$$anonfun$applyOrElse$2$$anonfun$apply$2.apply(Routes.scala:293)
    at router.Routes$$anonfun$routes$1$$anonfun$applyOrElse$2$$anonfun$apply$2.apply(Routes.scala:293)
    at play.core.routing.HandlerInvokerFactory$$anon$4.resultCall(HandlerInvoker.scala:157)
    at play.core.routing.HandlerInvokerFactory$$anon$4.resultCall(HandlerInvoker.scala:156)
    at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$14$$anon$3$$anon$1.invocation(HandlerInvoker.scala:136)
    at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:73)
    at play.http.HttpRequestHandler$1.call(HttpRequestHandler.java:54)
    at play.db.jpa.TransactionalAction.lambda$call$4(TransactionalAction.java:28)

为什么呢?我怎么绑它?

0 个答案:

没有答案