I have similar tables:
I need to create JSP files that contains measured values for Device.
My idea is web page (table) like this:
Device:
SensorA:
Temp (table row 1)
Temp (table row 2)
Temp (table row n)
SensorB:
Hum (table row 1)
Hum (table row 2)
Hum (table row n)
There is my code:
#Entity
#Table(name="device")
public class Device implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
#Column(length=45)
private String title;
#OneToMany(mappedBy="device")
private List<Value> values;
public Device() {
}
// getters and setters....
}
#Entity
#Table(name="`values`")
public class Value implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
#org.hibernate.annotations.Source(SourceType.DB)
#org.hibernate.annotations.Generated(value = GenerationTime.INSERT)
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "date", insertable = true, updatable = false)
private Date date;
#OneToMany(mappedBy="value")
private List<SensorA> sensorA;
#OneToMany(mappedBy="value")
private List<SensorB> sensorB;
#ManyToOne
#JoinColumn(name="device_id", nullable=false)
private Device device;
public Value() {
}
// getters and setters...
}
#Entity
#Table(name="sensor_a")
public class SensorA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
#Column(name="TEMP", nullable=false)
private float temp;
#ManyToOne
#JoinColumn(name="values_id", nullable=false)
private Value value;
public SensorA() {
}
// getters and setters...
}
#Entity
#Table(name="sensor_b")
public class SensorB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
#Column(name="HUM", nullable=false)
private float hum;
#ManyToOne
#JoinColumn(name="values_id", nullable=false)
private Value value;
public SensorB() {
}
// getters and setters...
}
#RequestMapping("/value")
#Controller
public class ValueController {
#Autowired
DeviceManager deviceManager;
#RequestMapping(value="/{date}", method=RequestMethod.GET)
public String getPage(Model model, #PathVariable("date") Date date) {
Device d = deviceManager.findByDate(date);
List<Value> values = d.getValues();
model.addAttribute("values", values);
return "value";
}
}
And JSP:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# page session="false" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<h3>Values with datas</h3>
<div>
<table>
<tr>
<th>value id</th>
<th>sensor_a id</th>
<th>temp</th>
</tr>
<c:forEach var="value" items="${values}">
<tr>
<td><c:out value="${value.id}" /></td>
<td><c:out value="${value.sensorA.id}" /></td>
<td><c:out value="${value.sensorA.temp}" /></td>
</tr>
</c:forEach>
</table>
</div>
How can I send all values with all sensorA and sensorB sensors to JSP? And how can I access it? My JSP writes only table header.
Related
i have a spring boot application, and when i load the data in thymeleaf it doesn't load, it's empty. I'm using H2, so every time i launch the app i do some inserts to test, but it never loads the data. I've tried the enpoints with Postman, and they all work. I'm thinking it's something with the method i'm using, but i don't know yet.
Here's my application models:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "estudiante")
public class Estudiante {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "estudiante_generator")
private Long id;
#Column(name = "nombre")
private String nombre;
#Column(name = "apellido")
private String apellido;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "profesor_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Profesor profesor;
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "profesor")
public class Profesor {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "profesor_generator")
private Long id;
#Column(name = "nombre")
private String nombre;
#Column(name = "apellido")
private String apellido;
#Column(name = "curso")
private String curso;
public Profesor(String nombre, String apellido, String curso){
this.nombre = nombre;
this.apellido = apellido;
this.curso = curso;
}
}
The controller for the index, and the controller for the backend:
#GetMapping("/index")
public String mostrarProfesores(Model model){
List<Profesor> profesor = profesorRepository.findAll();
model.addAttribute("profesores", profesor);
return "index";
}
#GetMapping("/profesores")
public ResponseEntity<List<Profesor>> getProfesores(){
List<Profesor> profesor = new ArrayList<Profesor>();
profesorRepository.findAll().forEach(profesor::add);
if(profesor.isEmpty()){
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(profesor, HttpStatus.OK);
}
And the thymeleaf template:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h2>Users</h2>
<table>
<thead>
<th>Nombre</th>
<th>Apellido</th>
</thead>
<tbody>
<th:block th:each="profesor : ${profesores}">
<tr>
<td>[[${profesor.nombre}]]</td>
<td>[[${profesor.apellido}]]</td>
</tr>
</th:block>
</tbody>
</table>
</div>
</body>
</html>
Any help is appreciated, thanks in advance for your help.
You should iterate the collection inside the <tr> label.
<tbody>
<tr th:each="profesor : ${profesores}">
<td th:text="${profesor.nombre}"></td>
<td th:text="${profesor.nombre}"></td>
</tr>
</tbody>
I am looking for a solution all day, but I still can not find anything.
When I create a book, how can I create an author and assign it to a book at the same time?
I have two entities
Book
#Data
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
#ManyToOne
private Author author;
}
Author
#Data
#Entity
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "author")
private Set<Book> books;
}
Controller
#Controller
public class BookController {
private BookRepository bookRepository;
public BookController(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#RequestMapping(value="/booklist", method= RequestMethod.GET)
public String bookList(Model model) {
model.addAttribute("books", bookRepository.findAll());
return "booklist";
}
#RequestMapping(value = "/add")
public String addBook(Model model){
model.addAttribute("book", new Book());
return "addbook";
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(Book book){
bookRepository.save(book);
return "redirect:booklist";
}
}
VIEW
<body>
<div>
<form th:object="${book}" th:action="#{save}" action="#" method="post">
<label for="title">Title</label>
<input type="text" id="title"
th:field="*{title}" />
<label for="author">Author</label>
<input type="text" id="author" th:field="*{author.name}" />
<input type="submit" value="Save"></input>
</form>
</div>
</body>
When I try to create a book I got this error
There was an unexpected error (type=Internal Server Error, status=500).
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
After i click submit button
it should look like this
Try adding cascede to Author in entity like this
#Data
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
#ManyToOne(cascade=CascadeType.ALL)
private Author author;
}
or use prepersist annotation on your entity
#PrePersist
protected void onCreate() {
//check author is exist if not persist the author first
}
I have 3 objects: User, Comment and StatusUpdate(news). This is the User...
#Entity
#Table(name = "users")
#PasswordMatch(message = "{register.repeatpassword.mismatch}")
public class SiteUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "email", unique = true)
#Email(message = "{register.email.invalid}")
#NotBlank(message = "{register.email.invalid}")
private String email;
#Transient
#Size(min = 5, max = 15, message = "{register.password.size}")
private String plainPassword;
#Column(name = "password", length = 60)
private String password;
#Column(name = "enabled")
private Boolean enabled = false;
#NotNull
#Column(name = "firstname", length = 20)
#Size(min = 2, max = 20, message = "{register.firstname.size}")
private String firstname;
#NotNull
#Column(name = "surname", length = 25)
#Size(min = 2, max = 25, message = "{register.surname.size}")
private String surname;
#Transient
private String repeatPassword;
#Column(name = "role", length = 20)
private String role;
public SiteUser() {
}
Here comes the StatusUpdate(you can call it piece of news or article). That has a site user that is the one who has created that article.
#Entity
#Table(name = "status_update")
public class StatusUpdate {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Size(min=5, max=255, message="{addstatus.title.size}")
#Column(name = "title")
private String title;
#Size(min=5, max=5000, message="{addstatus.text.size}")
#Column(name = "text")
private String text;
#Column(name = "added")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern="yyyy/MM/dd hh:mm:ss")
private Date added;
#OneToOne(targetEntity = SiteUser.class)
#JoinColumn(name="user_id")
private SiteUser siteUser;
#PrePersist
protected void onCreate() {
if (added == null) {
added = new Date();
}
}
public StatusUpdate() {
}
And the Comment which can be done by any registered user, right? As you will notice the Comment has no User object to avoid circular references.
#Entity
#Table(name = "comments")
public class Comment {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "statusupdateid")
private StatusUpdate statusUpdate;
#Column(name = "commenttext")
private String commenttext;
#Column(name = "commentdate")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "yyyy/MM/dd hh:mm:ss")
private Date commentdate;
#Column(name = "userid")
private Long userid;
public Comment() {
}
Now I would like to show in my JSP an article, with all the related comments and each of them belong to a different user. Can I use a HashMap to relate the users and their comments? I do not see how.
#RequestMapping(value ="/viewonestatus/{id}")
public ModelAndView viewOneStatus(#PathVariable("id") Long id) {
StatusUpdate status = statusUpdateService.get(id);
int countComments = commentService.countStatusComments(status);
List<Comment> comments = commentService.readAllComments(status);
ModelAndView modelAndView = new ModelAndView();
for (Comment comment: comments){
SiteUser user = userService.get(comment.getUserid());
modelAndView.getModel().put("user", user);
}
modelAndView.getModel().put("commentscounter", countComments);
modelAndView.getModel().put("status", status);
modelAndView.getModel().put("comments", comments); //!!
modelAndView.setViewName("app.viewonestatus");
return modelAndView;
}
As you expect, when my JSP shows just one user (the last one) for all the comments, but I can not relate all the Comments with the corresponding Users
<table class="table table-hover">
<c:forEach var="comment" items="${comments}">
<tr>
<td>
<div class="col-sm-2 sm-margin-bottom-40">
<img class="img-responsive profile-img margin-bottom-20" id="profilePhotoImage" src="/profilephoto/${comment.userid}" />
</div>
<h4>
${user.firstname} ${user.surname}
<span>
<!-- <span>${counterUserMap[comment.key]}</span> -->
5 hours ago / Reply
</span>
</h4>
<p>
<fmt:formatDate pattern="EEEE d MMMM y 'at' H:mm:ss" value="${comment.commentdate}" />
</p>
<p>${comment.commenttext}</p>
</td>
</tr>
</c:forEach>
I do not want to use JSON. I'm thinking about an anonymous class with all the stuff inside. Well, I'm open to your thoughts. Thanks.
Shokulei answer was the solution:
Since you have the userid, you can link it using the #ManyToOne annotation. This would be the most ideal way. But if you really don't want to link them, then you can create a new #Transient SiteUser siteUser; attribute in Comment class. And then in your for loop, you can use comment.setSiteUser(user); instead of modelAndView.getModel().put("user", user);. Hope this will help.
Thanks Shokulei
My application has two entity Product and Category. When add product , user choose the category that product belong to. But when save the product to data base i meet the error
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation
the content of entity is
Category.java
#Entity
#Table(name="category")
public class Category {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name="category_name")
private String categoryName;
#Column(name="description")
private String description;
#OneToMany(mappedBy = "category", fetch=FetchType.LAZY)
private Set<Product> products;
//getter and setter method
}
Product.java
#Entity
#Table(name="product")
public class Product {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column(name="name")
#NotNull
#NotEmpty
private String name;
#Column(name="description")
private String description;
#Column(name="manufacture")
private String manufacture;
#Column(name="price")
private long price;
#Column(name="image_name")
private String imageName;
#ManyToOne
#JoinColumn(name = "category_id", referencedColumnName = "id", nullable = false)
Category category;
//getter and setter method
}
ProductDAO.java
#Repository("ProductDAO")
#Transactional
public class ProductDAO {
#PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void create(Product product) {
entityManager.merge(product.getCategory());
entityManager.persist(product);
}
//other method
}
my jsp file
<form:form method="post" commandName="product" action="add.html" enctype="multipart/form-data">
Productname <form:input path="name"/>
<form:errors path="name" class ="error"/><br>
description <form:input path="description"/><br>
price <form:input path="price"/><br>
manufacture <form:input path="manufacture"/><br>
Category
<form:select path="category">
<form:options items="${categories}" itemValue="id" itemLabel="categoryName" />
</form:select>
<form:errors path="category" class ="error"/><br>
<br/>
Product image<input type="file" name="file" />
<form:errors path="imageName" class ="error"/><br>
<input type="submit" class="register" value="Save">
</form:form>
my Converter
public class CategoryConverter implements Converter<String, Category>{
#Autowired
private CategoryService categoryService;
public Category convert(String id) {
return categoryService.findById(Long.valueOf(id));
}
}
thank for any help
please add (cascade=CascadeType.ALL) into category field mapping of Product
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "category_id", referencedColumnName = "id", nullable = false)
Category category;
and remove this line in ProductDAO:
entityManager.merge(product.getCategory());
NOTE: if your product's category is an existing one, you should load it first then set it to your product, this is normal flow. Do not new duplicated Category object.
This my fixed code
#Transactional
public void create(Product product) {
Category category=categoryDAO.findById(product.getCategory().getId());
category.getProducts().add(product);
categoryDAO.edit(category);
product.setCategory(category);
this.productDAO.create(product);
}
In my spring application, the forms for insert/update a entity in the database have a structure similar to this:
<jsp:include page="../../common/cadastrar.jsp">
<jsp:param name="entity" value="Usuario"/>
<jsp:param name="arguments" value="login"/>
<jsp:param name="arguments" value="senha"/>
<jsp:param name="arguments" value="first_name"/>
<jsp:param name="arguments" value="last_name"/>
<jsp:param name="arguments" value="email"/>
</jsp:include>
which redirect to this shared jsp page (common to all the views):
<c:url value="${param.entity}/cadastra" var="cadastra"/>
<form:form class="form" role="form" method="post" action="${cadastra}">
<table>
<c:forEach var="item" items="${paramValues.arguments}">
<c:choose>
<c:when test="${item == 'senha'}">
<tr>
<td><form:label path="${item}">${item}</form:label></td>
<td><form:input path="${item}" type="password"/></td>
</tr>
</c:when>
<c:otherwise>
<tr>
<td><form:label path="${item}">${item}</form:label></td>
<td><form:input path="${item}"/></td>
</tr>
</c:otherwise>
</c:choose>
</c:forEach>
<tr>
<td colspan="2">
<button type="submit" class="btn btn-lg btn-primary">Cadastrar</button>
</td>
</tr>
</table>
</form:form>
When my entity class have only primitive attributes (Integer, String, etc), this code works fine. But I can't figure out how to do the same for classes like that:
#Entity
#Table(name="cliente")
public class Cliente extends Entidade {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#OneToOne
#JoinColumn(name="fk_usuario")
private Usuario usuario;
#Column(name="documento")
private String documento;
#Column(name="cpf")
private String cpf;
#Column(name="cnpj")
private String cnpj;
#ManyToMany
#JoinTable(name="endereco_entrega", joinColumns={#JoinColumn(name="fk_cliente")}, inverseJoinColumns={#JoinColumn(name="fk_endereco")})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Endereco> endereco;
#ManyToMany
#JoinTable(name="pedido_cliente", joinColumns={#JoinColumn(name="fk_cliente")}, inverseJoinColumns={#JoinColumn(name="fk_pedido")})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Pedido> pedido;
}
where some of the attributes are other entities. Anyone can point me a direction to do this?
UPDATE 1
Usuario.java
#Entity
#Table(name="usuario")
public class Usuario extends Entidade {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name = "login")
private String login;
#Column(name = "senha")
private String senha;
#Column(name="first_name")
private String first_name;
#Column(name="last_name")
private String last_name;
#Column(name="email")
private String email;
#ManyToMany
#JoinTable(name="role_members", joinColumns={#JoinColumn(name="fk_user")}, inverseJoinColumns={#JoinColumn(name="fk_role")})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Role> Autorizacao = new ArrayList<Role>();
}
Endereco.java
#Entity
#Table(name="endereco")
public class Endereco {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="logadouro")
private String logradouro;
#Column(name="numero")
private String numero;
#Column(name="complemento")
private String complemento;
#Column(name="bairro")
private String bairro;
#Column(name="cidade")
private String cidade;
#Column(name="estado")
private String estado;
#Column(name="cep")
private String cep;
}
Pedido.java
#Entity
#Table(name="pedido")
public class Pedido {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#ManyToMany
#JoinTable(name="produtos_do_pedido", joinColumns={#JoinColumn(name="fk_pedido")}, inverseJoinColumns={#JoinColumn(name="fk_produto")})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Produto> produto;
#ManyToMany
#JoinTable(name="cobranca_do_pedido", joinColumns={#JoinColumn(name="fk_pedido")}, inverseJoinColumns={#JoinColumn(name="fk_cobranca")})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Cobranca> cobranca;
}