I really dont understand much of How Play Framework interact with Java (i use eclipse as IDE)
so please bear with me if my explanation is a bit incomprehensible
what i am trying to do is a 1-page webpage (localhost:9000) that could look like this:
http://i.stack.imgur.com/JtRFF.png (i only have 1 rep so i think can't put image; just a link)
THINGS I NEED TO KNOW:
1) How Does HTTP Methods interact with Playframework
2) How can I Delete, Edit entries
currently What i only know is how to populate students
code from controllers.Application.Java:
public static Result addStudents(){
Student student = Form.form(Student.class).bindFromRequest().get();
student.save();
return redirect(routes.Application.index());
}
public static Result getStudents(){
List<Student> students = new Model.Finder(String.class, Student.class).all();
return ok(toJson(students));
}
code from models.Student.java
#Entity
public class Student extends Model{
#Id
public String Id;
public String name;
public String course;
}
code from views.index.scala.html (I use Java not scala but i really don't know about the difference so i retained the intex.scala.html)
#main("Welcome to Play") {
<form action="#routes.Application.addStudents()" method="post">
<input name="name">
<input course="course">
<input type="submit">
</form>
}
code from conf.evolutions.routes
POST /student controllers.Application.addStudents()
GET /student controllers.Application.getStudents()
This completely depends on your needs. You will probably need to learn some ajax, and then learn how to work with requests in the play framework. You can learn ajax basics here.Here you can learn to parse the data you can send with ajax.
For example:
Javascript
var req = new XMLHttpRequest();
var data = "{"Hi"};
req.open("GET", "http://localhost:9000/service, true);
req.send(data);
Java
#BodyParser.Of(BodyParser.Json.class)
public static Result index() {
RequestBody body = request().body();
return ok(body.asJson()).as("text/json");
}
Also, you will need to import play.mvc.Http. I am not sure about the javascript, my ajax is a little rusty.
This will simply echo the response back , but it shows the basics.
Related
So far in my Java code with Spring Boot I was using models, or POJO objects to achieve better control of my objects, etc. Usually I am creating Entities, Repositories, Services, Rest controllers, just like documentation and courses are suggesting.
Now however I am working with Thymeleaf templates, HTML a bit of Bootstrap and CSS in order to create browser interface. For methods in #Controller, as parameter, I am passing Model from Spring Model UI like this:
#GetMapping("/employees")
private String viewAllEmployees(Model employeeModel) {
employeeModel.addAttribute("listEmployees", employeeService.getAllEmployees());
return "employeeList";
}
My question is: How can I use my POJO objects instead of org.springframework.ui.Model;?
My first guess was this:
public class EmployeeModel implements Model{
private long employeeId;
private String firstName;
private String lastName;
private String email;
private String phone;
private long companyId;
//getter and setter methods
}
And in order to do that I have to #Override Model methods which is fine with me. And it looks like Java, Spring etc. does not complain in compile time, and I can use this POJO object in my #Controller like this:
#Controller
public class EmployeeController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/employees")
private String viewAllEmployees(EmployeeModel employeeModel) {
employeeModel.addAttribute("listEmployees", employeeService.getAllEmployees());
return "employeeList";
}}
I run the code and it starts, shows my /home endpoint which works cool, however when I want to go to my /employees endpoing where it should show my eployees list it throws this:
Method [private java.lang.String com.bojan.thyme.thymeApp.controller.EmployeeController.viewAllEmployees(com.bojan.thyme.thymeApp.model.EmployeeModel)] with argument values:[0] [type=org.springframework.validation.support.BindingAwareModelMap] [value={}] ] with root cause java.lang.IllegalArgumentException: argument type mismatch
exception.
Please note that Rest controller is working perfectly in browser and Postman.
Is it possible that String as a method is the problem? Should my method be of some other type like List<EmployeeModel> or maybe EmployeeModel itself? If it is so, how to tell the method that I want my employeeList.html to be returned?
I sincerely hope that someone can halp me with this one :)
How can I use my POJO objects instead of org.springframework.ui.Model;?
I don't think that is the best practice when you are working with Thymeleaf. According to their documentation, you should attach your Objects to your Model. So in your controller you would be manipulating models that contain your Pojos.
Example:
#RequestMapping(value = "message", method = RequestMethod.GET)
public ModelAndView messages() {
ModelAndView mav = new ModelAndView("message/list");
mav.addObject("messages", messageRepository.findAll());
return mav;
}
You should always use org.springframework.ui.Model as argument. This class is basically a Map with key/value pairs that are made available to Thymeleaf for rendering.
Your first example is how you should do it:
#GetMapping("/employees") //<1>
private String viewAllEmployees(Model model) {
model.addAttribute("employees", employeeService.getAllEmployees()); // <2>
return "employeeList"; // <3>
}
<1> This is the URL that the view will be rendered on
<2> Add any Java object you want as attribute(s) to the model
<3> Return the name of the Thymeleaf template. In a default Spring Boot with Thymeleaf application, this will refer to the template at src/main/resources/templates/employeeList.html. In that template, you will be able to access your model value with ${employees}.
I have a thymeleaf form and spring boot back-end. I have a model class which has defiened it's getters and setters little bit deferent name. so when Im going to take that model and get its fields as form input fields thymeleaf can not recognised them as fields.
here is my modal,
public class scDto {
private Integer region;
private boolean isAmt;
public scDto() {
}
public Integer getRegion() {
return this.region;
}
public void setRegion(Integer region) {
this.region = region;
}
public boolean isAmt() {
return this.isAmt;
}
public void setAmt(boolean amt) {
this.isAmt = amt;
}
here is my form input field,
<input type="text" th:field="*{sc.isAmt}"/>
here is the error,
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (price:331)
Form is working well for region field. but it does not work for Amt field.
Maybe I can fix this if I changed isAmt() get method to getIsAmt(). But I cant change any method name of the modal class because that class already compiled and I used it via a jar file. Is there anyway to solve this problem.
(Copied from the comments under the question)
I guess you can try to refer to this variable using the {sc.amt}.
More information about the javabeans notation you can read here: stackoverflow.com/a/17066599/7629196
Seeing your DTO it has only 2 fields
public class scDto {
private Integer region;
private boolean isAmt;
public boolean isAmt() {
return this.isAmt;
}
...
}
As per convention
For method name like this
boolean isXyz()
you will read it like xyz
So this line
<input type="text" th:field="*{sc.isAmt}"/>
should be
<input type="text" th:field="*{sc.amt}"/>
Credit also goes to Ruslan K for mentioning this in Comment.
Just adding to add more clarity.
I'm trying to use the automatic binding feature of Play, without success. I'm developing in Java, on Eclipse 4.4 Luna.
Here is my form :
<h2>Create a new user</h2>
<form action="#routes.Backend.createUser()" method="post">
First Name
<input type="text" name="firstName" />
Last Name
<input type="text" name="lastName" />
E-mail
<input type="email" name="email" />
PIN
<input type="number" name="pin" />
Status
<input type="text" name="status" />
Is guest?
<input type="checkbox" name="isGuest" />
<input type="submit" value="Create user" />
</form>
Here is my class "Users":
#Entity
public class Users extends Model {
// Database columns
#Id
public int userId;
public String firstName;
public String lastName;
public String email;
public int pin;
public String status;
public boolean isGuest;
}
And here is my controller:
public class Backend extends Controller {
public static Result createUser() {
Form<Users> form = Form.form(Users.class).bindFromRequest();
if (form.hasErrors()) {
// doSomething()
} else {
Users u = form.get();
u.save();
}
// TESTING
// Checking the content of the request
DynamicForm requestData = Form.form().bindFromRequest();
String firstName = requestData.get("firstName");
String lastName = requestData.get("lastName");
// Printing the content works, I am able to see the correct values
System.out.println(firstName); // Bob
System.out.println(lastName); // Smith
// This somehow doesn't work...
System.out.println(u.firstName); // NULL
System.out.println(u.lastName); // NULL
System.out.println(u.userId); // Correctly generated
// END OF TESTING
return redirect(routes.Backend.allUsers());
}
}
I wonder why the automatic binding of values doesn't work. I have made sure that the fields name in my form correspond to the attributes names in the class, and this should be enough for the form binding to work, right?
I am using Eclipse Luna, and I turned off automatic project build (I do it manually from the console). I know that sometimes Eclipse can cause issues because of that auto-build feature. Note: This was the way to go, but I didn't clean the project using the activator command, as user Dmitri suggested. Also, you only have to do this once, as long as you don't turn on the automatic build feature in Eclipse.
I have tried restarting Eclipse and the application several times, without success...
EDIT:
I tried using only String attributes for my Users class, since the requestData.get(String s) method returns a String. But still no success...
EDIT 2:
I'm going to bind the values manually... If anyone have an idea, please post :)
EDIT 3:
I've updated my code to follow the rules mentioned in the answer below
EDIT 4:
I can't get autobinding working only when using my Postgresql 9.3 database. When I use in-memory database, everything works smoothly. Also, since there was no JDBC driver for Java 8 and postgresql 9.3, I'm using an older version of the driver (actually the driver is on PGSQL's website, but I couldn't get it working with Play). I will have to check what happens with another DB, then I'll report back here!
EDIT 5:
I tried to create my custom data binder like this:
Formatters.register(User.class, new Formatters.SimpleFormatter<User>() {
#Override
public User parse(String arg0, Locale arg1) throws ParseException {
User u = new Model.Finder<Integer, User>(Integer.class, User.class).byId(Integer.parseInt(arg0));
return u;
}
#Override
public String print(User arg0, Locale arg1) {
return "User : " + arg0.firstName;
}
});
... but it didn't work!
EDIT 6:
User Dmitri has found a working solution: you have to compile the project outside of Eclipse. It seems that there is some incompatibilities between Eclipse's compilator and Play! Framework's compilator...
I have been struggling with exactly the same problem: bindFromRequest returned nulls for "name" field. I did exactly the same what a guy in this Play for Java introduction video did: youtube.com/watch?v=bLrmnjPQsZc . But still no luck.
I've been working on Windows 7 with JDK 1.8. IDE: Eclipse 4.4.0. And I run activator through cygwin.
This is what solved the problem for me:
In Eclipse: Project -> Build Automatically - > turn off
In cygwin:
./activator clean;
./activator compile;
./activator run;
After this, bindFromRequest binds name correctly and puts it into the database.
Create getters/setters for your data model. It has solved my problem.
In your code you have :
Users u = Form.form(Users.class).bindFromRequest().get();
Try with this instead :
Users user = new Users();
Form <Users> u = Form.form(Users.class).fill(user).bindFromRequest();
EDIT :
May be the problem is the input types you're using. Try to generate your form like this :
#form(routes.Backend.createUser()) {
<label>First Name:</label> #inputText(userForm("first_name")) <br />
<label>Last Name:</label> #inputText(userForm("first_name")) <br />
<label>Email:</label> #inputText(userForm("email")) <br />
<label>Pin:</label> #inputText(userForm("pin")) <br />
<label>Status:</label> #inputText(userForm("status")) <br />
<label>Is Guest:</label> #checkbox(userForm("is_guest")) <br />
<input type="submit" value="Create user" />
}
Then in User Entity : try to change all columns type to String
#Entity
public class Users extends Model {
// Database columns
#Id
public int user_id;
public String first_name;
public String last_name;
public String email;
public String pin;
public String status;
public String is_guest;
}
In your controller :
public class Backend extends Controller {
public static Result createUser() {
Form <Users> userForm = Form.form(Users.class).bindFromRequest();
Users user = userForm .get();
user.save();
}
}
There is absolutely no link between the binding and your database. Do not follow #blackbishop's advice telling you to change all the fields of your model to String. That's a very bad idea, if there are different types, there is a reason...
Moreover, Ebean (supposing you're using it) or JPA generate database column types according to your Java properties type. Why would you store a 0 or a 1 in a varchar column ?
Follow these rules :
Use a singular name for your models (User instead of Users)
Always use camel case for your properties, no underscores (firstName instead of first_name, lastName instead of last_name...)
Check errors before getting the value after binding
That should give you this :
public static Result createUser() {
Form<User> form = Form.form(User.class).bindFromRequest();
if (form.hasErrors()) {
// Do what you have to do (i.e. : redirect to the form with a flash message)
}
User u = form.get();
u.save();
return redirect(routes.Backend.allUsers());
}
By the way, in your testing lines, the user_id is correctly generated because you have no validation rules and this data comes from the database, not the form.
I solved this by Adding Setters and Getters.
If you have Entity/Model class you should add setters and getters.
If you have FormData classes add setters and getters for it as well.
So when you call
Form<YourFormData> formData = Form.form(YourFormData.class).bindFromRequest();
YourFormData formData = formData.get();
Your formData will now have all the values set.
Hope this helps!
I know this post has an accepted answer but wanted to post my experience with this issue.
I had the same issue and performed all the steps mentioned in the answer above i.e. Eclipse build automatically and then clean and compile through the activator. However, this did not work. I tried many different ways and even created a project from scratch without creating any Eclipse dependencies. Still, it did not work.
Then, I looked at my model and decided to try by changing the case of my property names, and then voila! It worked!
Here is what my model looked like BEFORE:
public class Test {
public String FirstName;
public String LastName;}
Now, I changed it to look like this:
public class Test {
public String firstName;
public String lastName;}
Just wanted to point this out since it is not obvious and I am coming from .Net
I have a classic ASP page (VBScript) calling a Java Webservice and I am building the XML myself. I'm not an expert at XML and am having trouble building a HashMap. Whenever I send the XML to the service, the map does not get populated with anything. This is currently what I have:
My Object:
public class QueryParameter {
private String parameterType = "";
private String parameterValue = "";
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
public String getParameterValue() {
return parameterValue;
}
public void setParameterValue(String parameterValue) {
this.parameterValue = parameterValue;
}
}
My XML:
<queryParameters>
<entry>
<key>1</key>
<value>
<QueryParameter>
<parameterType>String</parameterType>
<parameterValue>this is a parameter</parameterValue>
</QueryParameter>
</value>
</entry>
</queryParameters>
I'm assuming my XML is incorrect and that is why the parameter is set as an empty Map when the request gets to the web service. Any help would be appreciated! Thank you!
EDIT:
After loading the service wsdl into soapUI and viewing the call generated from there, I noticed that soapUI didn't know how to format the XML for the HashMap either. Perhaps I was implementing it incorrectly from my service.
I modified my service to use an ArrayList instead of a HashMap and am able to generate the XML for an ArrayList successfully. This will work for my problem, but if someone knows why I was unable to implement a HashMap, I would be curious to know the answer.
Thanks!
You set the content type of the response to "text/xml"?
<% response.ContentType="text/xml" %>
Edit:
Look if this link help you.
Utilizing the Dictionary Object
First of all I'm newbie in Struts.
I've a class:
public class Articulo {
private int codigo;
private String descripcion;
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
}
which is populated with values in a dispatcher. In the dispatcher I've
private Articulo articulo;
.......
public Articulo getArticulo() {
return articulo;
}
public void setArticulo(Articulo articulo) {
this.articulo = articulo;
}
There is also a JSP with
<s:property value="articulo"/>
which read ok the articulo. Also works articulo
<s:property value="articulo.codigo"/>
But now I want from that jsp forward the entire object articulo to another action.
I can do
<s:hidden name="articulo.codigo" value="%{articulo.codigo}"/>
<s:hidden name="articulo.descripcion" value="%{articulo.descripcion}"/>
and that works fine, but is there anyway to do something like
<s:hidden name="articulo" value="%{articulo}"/>
So, is there anyway to get the object from JSP without setting all the properties of it?
there are 2 points:
Problem: you can't transfer object using <s:hidden />, all the parameter, what are transfered with HTTP should be string. Since you cannot convert this object to String, you can't transfer it using HTTP either.
Solution: You can put your object into session, so that you can access it anytime you want. here is an EXAMPLE
Yes, you can transfer object in two ways either by parameter or store it in session and access it whenever you need it.
<jsp:forward page="URL" >
<jsp:param name="ParamName1" value="YourObject" />
</jsp:forward>
Visit here for more detail.
http://www.gulland.com/courses/jsp/actions/forward
Keeping the object information in sessions is usually the preferred method.
But an alternative option is to create your own Type Converter.
Create a type converter by extending StrutsTypeConverter. The
Converter's role is to convert a String to an Object and an Object to
a String.
By doing so, you could so something like <s:hidden name="articulo" value="%{articulo}"/>
Keep in mind this method is insecure as the object values will be printed out as String in the hidden tag and can be seen through the browser.
But the advantage is that this method works across different sessions if you have a need for such a thing.