In my spring project, Hibernate is used to manage the access to the database. For this, I have the tradicional schema using Entity and Dao classes, which are used by my service classes. am facing problems when I need remove a row from some table in my database. For instance, follow the code below:
remove.jsp
<c:url value="/usuario/listagem" var="listagem"/>
<c:url value="/permissao/remove" var="removePermissao"/>
<form class="form" role="form" action="${removePermissao}" method="post">
<div class="alert alert-warning" id="pergunta">
Tem certeza que quer excluir o grupo de permissões <strong><c:out value="${permissao.nome}"/></strong>?
<input type="hidden" name="id" value="<c:out value="${permissao.id}"/>">
<button type="submit" class="btn btn-lg btn-link"><span class="glyphicon glyphicon-ok"></span></button>
<button type="button" class="btn btn-lg btn-link link" data-action="${listagem}"><span class="glyphicon glyphicon-remove"></span></button>
</div>
</form>
<div id="yes" class="alert alert-success" style="display: none;">
<strong>Pronto!</strong> Permissão excluida com sucesso.
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
</div>
<div id="not" class="alert alert-danger" style="display: none;">
<strong>Erro!</strong> Não foi possivel excluir a permissão.
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
</div>
method remove() from controller
#RequestMapping(value="remove", method=RequestMethod.POST)
#ResponseBody
public String remove(HttpServletRequest request, HttpServletResponse response) {
if(permissao.remove(request, response))
return "yes";
else
return "not";
}
method remove() from service class
#PreAuthorize("hasPermission(#user, 'altera_permissao')")
#Transactional
public boolean altera(HttpServletRequest request, HttpServletResponse response) {
String id_usuario = request.getParameter("usuario");
String id_permissao = request.getParameter("grupo");
String possui = request.getParameter("possui");
if(possui.equals("yes")) {
Usuario user = usuario.findById(Integer.valueOf(id_usuario).intValue());
user.getAutorizacao().add(grupo_permissao.findById(Integer.valueOf(id_permissao).intValue()));
return usuario.merge(user);
}
else {
Usuario user = usuario.findById(Integer.valueOf(id_usuario).intValue());
int max = user.getAutorizacao().size();
for(int i=0; i<max; i++) {
if(user.getAutorizacao().get(i).equals(grupo_permissao.findById(Integer.valueOf(id_permissao).intValue()))) {
user.getAutorizacao().set(i, null);
}
}
return usuario.merge(user);
}
}
#PreAuthorize("hasPermission(#user, 'remove_permissao')")
#Transactional
public boolean remove(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
GrupoPermissao novo = grupo_permissao.findById(Integer.valueOf(id).intValue());
novo.setPermissao(null);
return grupo_permissao.remove(novo);
}
In the first method, altera(...), the second block of code from if...else should remove a permission fromthe user. The second method remove a role created by the user (roles in my project are a set of permissions).
The problem in first method is that when I try remove a row, a new one is inserted instead. In the second method, I am not able to remove the element because the system return an error of violation foreign key.
Anyone can help with some information of jow I should modify this method to accomplish the desired function?
ps.: my entity class related to the example above is:
Permissao.java
#Entity
#Table(name="permission")
public class Permissao {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
#Column(name="nome")
private String nome;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
GrupoPermissao.java
#Entity
#Table(name="role")
public class GrupoPermissao {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
#Column(name="nome")
private String nome;
#ManyToMany
#JoinTable(name="role_permissions", joinColumns={#JoinColumn(name="fk_role")}, inverseJoinColumns={#JoinColumn(name="fk_permission")})
#LazyCollection(LazyCollectionOption.FALSE)
private List<Permissao> permissao = new ArrayList<Permissao>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public List<Permissao> getPermissao() {
return permissao;
}
public void setPermissao(List<Permissao> permissao) {
this.permissao = permissao;
}
}
UPDATE 2
My final code is this:
#PreAuthorize("hasPermission(#user, 'altera_permissao')")
#Transactional
public boolean altera(HttpServletRequest request, HttpServletResponse response) {
String id_usuario = request.getParameter("usuario");
String id_permissao = request.getParameter("grupo");
String possui = request.getParameter("possui");
if(possui.equals("not")) {
Usuario user = usuario.findById(Integer.valueOf(id_usuario).intValue());
user.getAutorizacao().add(grupo_permissao.findById(Integer.valueOf(id_permissao).intValue()));
return usuario.merge(user);
}
else {
Usuario user = usuario.findById(Integer.valueOf(id_usuario).intValue());
int max = user.getAutorizacao().size();
int index[] = new int[max];
for(int i=0; i<max; i++)
index[i] = -1;
for(int i=0; i<max; i++) {
String p_user = user.getAutorizacao().get(i).getNome();
String p_comp = grupo_permissao.findById(Integer.valueOf(id_permissao).intValue()).getNome();
System.out.println(i+"->"+p_user+"=="+p_comp);
if(p_user.equals(p_comp)) {
index[i] = i;
}
}
for(int i=0; i<max; i++)
if(index[i] >= 0)
user.getAutorizacao().remove(i);
return usuario.merge(user);
}
}
Essentially you need to call session.getCurrentSession().delete(entity); to remove the entity using hibernate.
Or you can create a cutomer query using createQuery.
This is a great example of how to remove an object from table using hibernate:
http://examples.javacodegeeks.com/enterprise-java/hibernate/delete-persistent-object-with-hibernate/
EDIT 1:
Based on extra information provided where you want to remove permission relationship from user
then code you need to insert into either controller or pojo can be following:
User user = // allocate your user;
Permissao permissao = // allocate the permission you wish to remove
user.setPermissao(user.getPermissao().remove(permissaio);
then save the user object through saveOrUpdate() or Update() function.
This will remove the relationship to the permissao from the user. Keeps the user and permission in database.
Related
I have created a dynamic form in Thymeleaf which populates feedbacks from all users in a table format on the UI. The form is first called when the GET Api of the controller gets hit. Relevant code for the same is given below :
allfeedbacks.html
<h2>Dynamic form</h2>
<form action="#" th:action="#{/updatefb}" th:object="${feedbacklist}"
method="post">
<table>
<tr>
<th>Message</th>
<th>Status</th>
<th>Comments</th>
</tr>
<tr th:each="feedback : ${feedbacklist.myfbList}">
<td th:text="${feedback.message}" th:field="${feedback.message}">The
first name</td>
<td><select>
<option value="Pending"
th:selected="${feedback.status == 'Pending'}">Pending</option>
<option value="In Process"
th:selected="${feedback.status == 'In Process'}">In
Process</option>
<option value="Done" th:selected="${feedback.status == 'Done'}">Done</option>
</select></td>
<td><input type="text" placeholder="Enter Comment Here"
name="comments" th:text="${feedback.comment}"
th:field="${feedback.comment}" /></td>
</tr>
</table>
<button type="submit">Submit</button>
</form>
Basically I have created two beans, one is the Feedback.java bean while the other is FeedbackList.java bean. Code for the same is given below :
Feedback.java
#Entity
#Table(name = "feedback")
public class Feedback implements Serializable {
private static final long serialVersionUID = -3009157732242241606L;
#Id
private String id;
public String getId() {
return id;
}
public String getMessage() {
return message;
}
public String getStatus() {
return status;
}
public String getComment() {
return comment;
}
#Column(name = "message")
private String message;
#Column(name = "status")
private String status;
#Column(name = "comment")
private String comment;
public Feedback() {
}
public Feedback(String message, String status) {
this.message = message;
this.status = status;
this.id = UUID.randomUUID().toString();
}
FeedbackList.java
public class FeedbackList {
ArrayList<Feedback> myfbList;
public ArrayList<Feedback> getMyfbList() {
return myfbList;
}
public void setMyfbList(ArrayList<Feedback> myfbList) {
this.myfbList = myfbList;
}
}
Relevant code from my Controller class is as follows :
#RequestMapping(value = "/getAll", method = RequestMethod.GET)
public String getAllFeedbacks(#Valid FeedbackList feedbacklist,
BindingResult bindingResult, Model model) {
ArrayList<Feedback> fbarray = new ArrayList<>();
for (Feedback fb : repository.findAll()) {
fbarray.add(fb);
}
feedbacklist.setMyfbList(fbarray);
model.addAttribute("feedback", new Feedback());
model.addAttribute("feedbacklist", feedbacklist);
return "allfeedbacks";
}
#RequestMapping(value = "/updatefb", method = RequestMethod.POST)
public String updatefbStatus(#Valid FeedbackList feedbacklist,
BindingResult
bindingResult, Model model) {
//feedbacklist is coming as NULL below
for (Feedback fb : feedbacklist.getMyfbList()) {
System.out.println(fb.getComment());
System.out.println(fb.getMessage());
System.out.println(fb.getStatus());
}
// Code to update the database with the new status and comment would go
// here
return "result";
}
The form is getting properly rendered on the UI when I fire the Get request, however, when I make some changes in the form and submit it ( POST ), feedbacklist is coming as NULL. Could anyone please guide me with this ?
To use a list inside a form with Thymeleaf is a little bit more tricky, you need to use an specific syntax, here i show you an example.
<tr th:each="feedback : ${feedbacklist.myfbList}">
<td th:field="*{myfbList[__${feedbackStat.index}__].message}">The
first name
</td>
...//Same for others fields
</tr>
In thymeleaf you have to use the Stat object to say the array position where you want to set the value, also as normal fields inside an object you have to use the '*' notation.
I have a project based in Spring Web model-view-controller (MVC) framework. The version of the Spring Web model-view-controller (MVC) framework is 3.2.8.
This class
public class DeviceForm {
Device device;
List<String> selectedItems = Collections.emptyList();
public DeviceForm() {
super();
}
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public List<String> getSelectedItems() {
return selectedItems;
}
public void setSelectedItems(List<String> selectedItems) {
this.selectedItems = selectedItems;
}
}
and this
public class Device implements java.io.Serializable {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CRITERIA")
private BaseCriteria criteria;
public BaseCriteria getCriteria() {
return criteria;
}
public void setCriteria(BaseCriteria criteria) {
this.criteria = criteria;
}
}
and this
#Entity
#Table(name = "CRITERIA")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
#SequenceGenerator(name = "seqCriteria", sequenceName = "SEQ_CRITERIA", allocationSize = 1)
public abstract class BaseCriteria {
public BaseCriteria() {
super();
}
private Long id;
private String code;
private Date adoptionDate;
private Date expirationDate;
#Transient
public abstract String getGroupKey();
#Transient
public abstract Long getGroupId();
#Transient
public abstract String getRefColumnName();
#Id
#Column(name = "ID", unique = true, nullable = true)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqCriteria")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "CODE")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#Column(name = "ADOPTION_DATE")
#Temporal(TemporalType.TIMESTAMP)
public Date getAdoptionDate() {
return adoptionDate;
}
public void setAdoptionDate(Date adoptionDate) {
this.adoptionDate = adoptionDate;
}
#Column(name = "EXPIRATION_DATE")
#Temporal(TemporalType.TIMESTAMP)
public Date getExpirationDate() {
return expirationDate;
}
#Transient
public boolean isExpired() {
return getExpirationDate().before(new Date());
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
#Override
public String toString() {
return "BaseCriteria [id=" + id + ", code=" + code + ", adoptionDate="
+ adoptionDate + ", expirationDate=" + expirationDate + "]";
}
}
and the JSP
<form:form commandName="deviceForm"
name="deviceForm"
id="deviceFormId"
method="post"
action="${contextPath}/newdesign/manage/device/${deviceForm.device.id}"
htmlEscape="yes">
<div class="col-sm-6 text-right">
<button class="btn btn-primary" type="submit">Save device</button>
</div>
</div>
<c:forEach items="${deviceForm.device.productGroup.criteria}" var="criteria">
<div class="row">
<div class="col-md-3">
<form:radiobutton path="device.criteria.id" value="${criteria.id}"/>
<label for="basic-url">Criteria:</label>
<input value="${criteria.code}" disabled="disabled" class="form-control"/>
</div>
<div class="col-md-3">
<label for="basic-url">Adoption date:</label>
<input value="<fmt:formatDate type="date" value="${criteria.adoptionDate}" />" disabled="disabled" class="form-control"/>
</div>
<div class="col-md-3">
<label for="basic-url">Expiration Date:</label>
<input value="<fmt:formatDate type="date" value="${criteria.expirationDate}" />" disabled="disabled" class="form-control"/>
</div>
</div>
</c:forEach>
</form:form>
The controller:
/**
* #throws Exception
*
*/
#RequestMapping(value = { "/newdesign/manage/device/{appId}",
"/newdesign/manage/device/{appId}/"}, method = {RequestMethod.GET})
public String viewDevicesWithStatus(
#ModelAttribute("deviceForm") DeviceForm deviceForm,
#PathVariable Long appId,
HttpServletRequest request,
Model model ) throws Exception {
Device device = manageLicenseService.getDeviceById(appId, true);
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
deviceForm.setDevice(device);
fillModel (model, request, device);
return "cbViewDeviceInfo";
}
/**
* #throws Exception
*
*/
#RequestMapping(value = { "/newdesign/manage/device/{appId}",
"/newdesign/manage/device/{appId}/"}, method = {RequestMethod.POST})
public String saveDevicesWithStatus(
#ModelAttribute("deviceForm") DeviceForm deviceForm,
#PathVariable Long appId,
HttpServletRequest request,
Model model ) throws Exception {
Device device = manageLicenseService.getDeviceById(deviceForm.getDevice().getId());
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
//TODO: audit
device.updateDevice(deviceForm.getDevice());
manageLicenseService.saveDevice(device);
if (device.getCriteria()==null) {
device.setCriteria(device.getProductGroup().getCriteria().get(0));
}
deviceForm.setDevice(device);
fillModel (model, request, device);
return "cbViewDeviceInfo";
}
But I got following error when I submitted the form, on GET method I got same page without error
org.springframework.beans.NullValueInNestedPathException: Invalid property 'device.criteria' of bean class [com.tdk.iot.controller.newdesign.manage.DeviceForm]: Could not instantiate property type [com.tdk.iot.domain.criteria.BaseCriteria] to auto-grow nested property path: java.lang.InstantiationException
You get the error because in your form you have this:
<form:radiobutton path="device.criteria.id" value="${criteria.id}"/>
and in your POST handler you have this:
public String saveDevicesWithStatus(#ModelAttribute("deviceForm") DeviceForm deviceForm){
}
which means that the MVC framework will try to automatically set the property
deviceForm.device.criteria.id.
Now, because there is no existing DeviceForm in any scope then it will create a new one and of course device.getCriteria() returns null,
hence the exception.
You may think that the DeviceForm you created and populated in the GET handler will be used however Spring MVC is stateless so you
would need to store it in Session scope between requests for it to be re-used or otherwise rework your logic.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args
.... Given the above example where can theinstance come from? There
are several options.....[in the absence of any other option] It may
be instantiated using its default constructor
A better approach however is to change your form to be as below:
<form:radiobutton path="device.criteria" value="${criteria.id}"/>
and register a converter that would convert the submitted parameter and bind the corresponding entity instance.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert
#Component
public class StringToCriteriaConverter implements Converter<String, BaseCriteria> {
#Autowired
private CriteriaService service;
//source is the ID passed by the page
public BaseCriteria convert(String source) {
// lookup and return item with corresponding ID from the database
}
}
I have a problem with binding collections using spring and thymeleaf. Every time I send form, my object collections are set to null (User.postions), my example below:
My Controller:
#RequestMapping(value = urlFragment + "/add", method = RequestMethod.GET)
public String addPosition(Model model) {
HashSet<Position> positions = new HashSet<Position>(positionRepository.findByEnabledTrueOrderByNameAsc());
User employee = new User();
for (Position position : positions) {
employee.addPosition(position);
}
model.addAttribute("employee", employee);
return "crud/employee/add";
}
#RequestMapping(value = urlFragment + "/add", method = RequestMethod.POST)
public String processNewEmployee(Model model, #Valid #ModelAttribute("employee") User employee, BindingResult result) {
String templatePath = "crud/employee/add";
if (!result.hasErrors()) {
userRepository.save(employee);
model.addAttribute("success", true);
}
return templatePath;
}
And my employee form:
<form action="#" th:action="#{/panel/employee/add}" th:object="${employee}" method="post">
<div class="row">
<div class="col-md-6">
<label th:text="#{first_name}">First name</label>
<input class="form-control" type="text" th:field="*{userProfile.firstName}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label th:text="#{last_name}">Last name</label>
<input class="form-control" type="text" th:field="*{userProfile.lastName}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label th:text="#{email}">Email</label>
<input class="form-control" type="text" th:field="*{email}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label th:text="#{position}">Position</label>
<select th:field="*{positions}" class="form-control">
<option th:each="position : *{positions}"
th:value="${position.id}"
th:text="${position.name}">Wireframe
</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-5">
<div class="checkbox">
<button type="submit" class="btn btn-success" th:text="#{add_employee}">
Add employee
</button>
</div>
</div>
</div>
</form>
User entity:
#Entity
#Table(name="`user`")
public class User extends BaseModel {
#Column(unique = true, nullable = false, length = 45)
private String email;
#Column(nullable = false, length = 60)
private String password;
#Column
private String name;
#Column
private boolean enabled;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "user_role",
joinColumns = {#JoinColumn(name = "user_id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "role_id", nullable = false)}
)
private Collection<Role> roles = new HashSet<Role>();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "user_position",
joinColumns = {#JoinColumn(name = "user_id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "position_id", nullable = false)}
)
private Collection<Position> positions = new HashSet<Position>();
public User() {
}
public User(String email, String password, boolean enabled) {
this.email = email;
this.password = password;
this.enabled = enabled;
}
public User(String email, String password, boolean enabled, Set<Role> roles) {
this.email = email;
this.password = password;
this.enabled = enabled;
this.roles = roles;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Collection<Position> getPositions() {
return positions;
}
private void setPositions(Collection<Position> positions) {
this.positions = positions;
}
public boolean addPosition(Position position) {
return positions.add(position);
}
public boolean removePosition(Position position) {
return positions.remove(position);
}
public Collection<Role> getRoles() {
return roles;
}
private void setRoles(Collection<Role> roles) {
this.roles = roles;
}
public boolean addRole(Role role) {
return roles.add(role);
}
public boolean removeRole(Role role) {
return roles.remove(role);
}
#Override
public String toString() {
return User.class + " - id: " + getId().toString() + ", email: " + getEmail();
}
}
I have read somewhere that I have to create equals() and hashCode(), so I did it in my Position Entity.
public boolean equals(Position position) {
return this.getId() == position.getId();
}
public int hashCode(){
return this.getId().hashCode() ;
}
Here are data sent by post method:
And here is my result:
My spring version: 4.1.6.RELEASE
thymeleaf-spring4 version: 2.1.4.RELEASE
thymeleaf-layout-dialect version: 1.2.8
O course I wish positions to were HashCode with one element of object Position with id = 2.
Could you help me? What I am doing wrong?
It's because you're using ${position.id} for your option value. This means spring can't work out the relationship between the id used in the value and the actual Position objects. Try just ${position} for your value and it should work:
<select th:field="*{positions}" class="form-control">
<option th:each="position : *{positions}"
th:value="${position}"
th:text="${position.name}">Wireframe
</option>
</select>
(Make sure you've implemented hashCode and equals on your Position class)
If that still doesn't work you might have to implement a Formatter for Position, to make the conversion explicit. See this example thymeleafexamples-selectmultiple.
I had similar problem that I resolved by adding Formatter class and adding Formatter to the configuration of the MVC:
#Override
protected void addFormatters(FormatterRegistry registry){
registry.addFormatter(new PositionFormater());
...
}
and Position class formatter should look something like this:
PositionFormatter:
public class PositionFormatter implements Formatter<Position>{
/** String representing null. */
private static final String NULL_REPRESENTATION = "null";
#Resource
private PositionRepository positionRepository;
public PositionFormatter() {
super();
}
#Override
public String print(Position position, Locale locale) {
if(position.equals(NULL_REPRESENTATION)){
return null;
}
try {
Position newPosition = new Position();
newPosition.setId(position.getId());
return newPosition.getId().toString();
} catch (NumberFormatException e) {
throw new RuntimeException("Failed to convert `" + position + "` to a valid id");
}
}
#Override
public Position parse(String text, Locale locale) throws ParseException {
if (text.equals(NULL_REPRESENTATION)) {
return null;
}
try {
Long id = Long.parseLong(text);
Position position = new Position();
position.setId(id);
return position;
} catch (NumberFormatException e) {
throw new RuntimeException("Failed to convert `" + text + "` to valid Position");
}
}
}
In my case, these two solved all of the problems. I have several formatters, all I do is make one and add it to the config file (WebMVCConfig in my case)
Check my original post where I resolved this problem
Thanks Guys for answering my question. You help me a lot. Unfortunately I have to disagree with you in one thing. You have shown me example with:
newPosition.setId(position.getId());
The same example was in Andrew github repository. I think that this is bad practice to use setId() method. So I will present my solution and I will wait for some comments before I will mark it as an answer.
WebMvcConfig Class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.smartintranet")
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#PersistenceContext
private EntityManager entityManager;
// (....rest of the methods.......)
#Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addFormatter(new PositionFormatter(entityManager));
}
}
PositionFormatter class
public class PositionFormatter implements Formatter<Position> {
private EntityManager entityManager;
public PositionFormatter(EntityManager entityManager) {
this.entityManager = entityManager;
}
public String print(Position position, Locale locale) {
if(position.getId() == null){
return "";
}
return position.getId().toString();
}
public Position parse(String id, Locale locale) throws ParseException {
return entityManager.getReference(Position.class, Long.parseLong(id));
}
}
employeeForm.html
<div class="col-md-6">
<label th:text="#{position}">Position</label>
<select th:field="*{position}" class="form-control">
<option th:each="position : ${allPositions}"
th:value="${position.id}"
th:text="${position.name}">Wireframe
</option>
</select>
</div>
And last one, EmployeeController Class
#Controller
public class EmployeeController extends AbstractCrudController {
// (...rest of dependency and methods....)
#Transactional
#RequestMapping(value = urlFragment + "/create", method = RequestMethod.GET)
public String createNewEmployee(Model model) {
prepareEmployeeForm(model);
return "crud/employee/create";
}
#Transactional
#RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)
public String processNewEmployee(Model model, #ModelAttribute("employee") Employee employee, BindingResult result) {
if (!result.hasErrors()) {
// Look here it is important line!
entityManager.merge(employee.getUser());
}
prepareEmployeeForm(model);
return "crud/employee/create";
}
}
It is my solution. What is bad here? I think that line:
entityManager.merge(employee.getUser());
I can't use here:
userRepository.save(employee.getUser());
Because Position entity is detached, and when I use save method it runs in this situation em.persist() so I ran manually em.merge(). I know that this code is not perfect but I think that this solution is better then use setId(). I will be grateful for constructive critic.
One more time thanks Andrew and Blejzer for help without you I would not do it. I have marked yours answer as useful.
I'm currently working on a group project where we're supposed to handle the relation between Building and Room. The relation is OnetoMany, and we're currently able to show the relevant data from sql, but we're not able to display it in a good looking spreadsheet or table as intended. We would like to have the buildings and room sorted into a table, where each room shows connection to related building. How do we put our the HTML code in our (ShowRooms.jsp) jsp to get all rooms for building of choice by user, and then display all rooms by that building in a good-looking-table? In this state we get the data from our sql-database but just in a straight line instead of by a table which connects each room to the relevant building. Thanks in advance!
This is our code: BUILDING:
#Entity
#Table(name = "Building")
public class Building {
private String bname;
private List<Room> rooms; // Building can have many Rooms
#Id
#Column(name = "Bname")
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
#OneToMany(mappedBy = "building", fetch = FetchType.EAGER)
public List<Room> getRooms() {
return rooms;
}
public void setRooms(List<Room> rooms) {
this.rooms = rooms;
}
}
ROOM:
#NamedQueries({
#NamedQuery(name="Room.findByBname",
query="SELECT r FROM Room r WHERE r.bname LIKE :bname"),
})
#Entity
#Table(name = "Room")
public class Room implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private RoomId id;
private String bname;
private Building building;
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
#Id
public RoomId getId() {
return id;
}
public void setId(RoomId id) {
this.id = id;
}
#ManyToOne
#JoinColumn(name = "Bname", insertable = false, updatable = false)
public Building getBuilding() {
return this.building;
}
public void setBuilding(Building building) {
this.building = building;
}
}
ROOMID:
#Embeddable
public class RoomId implements Serializable {
private String bname;
private String rcode;
public RoomId() {
}
public RoomId(String bname, String rcode) {
this.bname = bname;
this.rcode = rcode;
}
#Column(name = "Bname", nullable = false)
public String getbname() {
return bname;
}
public void setbname(String bname) {
this.bname = bname;
}
#Column(name = "Rcode", nullable = false)
public String getrcode() {
return rcode;
}
public void setrcode(String rcode) {
this.rcode = rcode;
}
public boolean equals(Object other) {
if ((this == other)) {
return true;
}
if ((other == null)) {
return false;
}
if (!(other instanceof RoomId)) {
return false;
}
RoomId castOther = (RoomId) other;
return ((this.getbname() == castOther.getbname()) || (this.getbname() != null
&& castOther.getbname() != null &&
this.getbname().equals(castOther.getbname())))
&&
((this.getrcode() == castOther.getrcode()) || (this.getrcode() != null && castOther.getrcode() != null &&
this.getrcode().equals(castOther.getrcode())));
}
public int hashCode() {
return super.hashCode();
}
}
BUILDINGEAO:
#Stateless
public class BuildingEAOImpl implements BuildingEAOImplLocal {
#PersistenceContext(unitName = "LabEJBSql")
private EntityManager em;
public BuildingEAOImpl() {
// TODO Auto-generated constructor stub
}
public Building findByBname(String bname) {
return em.find(Building.class, bname);
}
}
FACADE:
#Stateless
public class Facade implements FacadeRemote, FacadeLocal {
#EJB
BuildingEAOImplLocal BuildingEAO;
#EJB
RoomEAOImplLocal RoomEAO;
public Facade() {
// TODO Auto-generated constructor stub
}
public List<Room> findRoomsByBname(String bname) {
return RoomEAO.findByBname(bname);
}
}
SERVLET:
#WebServlet("/TestClientServlet")
public class TestClientServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private FacadeLocal facade;
/**
* #see HttpServlet#HttpServlet()
*/
public TestClientServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("TestClientServlet-doGet");
out.close();
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String url = null;
// Get hidden field
String operation = request.getParameter("operation");
if (operation.equals("showrooms")) {
String bname = request.getParameter("txtBname");
List<Room> r = facade.findRoomsByBname(bname);
request.setAttribute("rooms", r);
url = "/ShowRooms.jsp";
} else if (operation.equals("searchbuilding")) {
System.out.println("TestClientServlet-searchbuilding");
url = "/SearchBuilding.jsp";
} else {
url = "/SearchBuilding.jsp";
}
System.out.println(url);
RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher(url);
dispatcher.forward(request, response);
}
*/
}
SEARCHBUILDING.JSP:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-
8859-1">
<title>Search Building</title>
</head>
<body>
<form action="/BuildRoomClientProject/TestClientServlet" method="post">
<table cellspacing="0" cellpadding="0" border="0" align="left">
<tr>
<td><h2>Search Building:</h2></td>
</tr>
<tr>
<td>
<input type= "text" name= "txtBname" size ="25" maxlength="25">
<input type="submit" name="submit" value="Search" />
</td>
<td></td>
</tr>
</table>
<input name="operation" value="showrooms" type="hidden">
</form>
</body>
</html>
SHOWROOMS.JSP:
<%# page contentType="text/html;charset=windows-1252"%>
<%# page import = "org.ics.ejb.Building" %>
<%# page import = "org.ics.ejb.Room" %>
<%# page import = "org.ics.ejb.RoomId" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>
Show Rooms
</title>
</head>
<body>
<h2>
Rooms:
</h2>
<%List<Room> r = (List<Room>)request.getAttribute("rooms"); %>
<% for (Room r1 : r){
out.println(r1.getBname() + " " + r1.getId().getrcode());
}%>
<p>
</p>
<form action="/BuildRoomClientProject/TestClientServlet" method="post">
<input type="submit" name="submit" value="Tillbaka">
<input name="operation" value="searchbuilding" type="hidden">
</form>
</body>
</html>
For your jpql, youldn't you use a GROUPBY combined with a GROUPBY directive?
Then for each table entry that is one you get render the bname (= BuildingName ??) as first row.
Then render your retrieved list as a table, a short example could be somehow this:
<table>
<c:forEach var="o" items="${objects}">
<tr>
<td>${o.bname}</td>
<td>${o.id}</td>
<td>${o.name}</td>
<td>${o.descriptio}</td>
</tr>
</c:forEach>
</table>
In fact, I just found this: displaying a list of entities in jsp file by using java searching for "jsp, listview, table"
I try to display a part of gallery's photo=> this is result when i did the search action. This result have avatar like a picture and infomation like username or email.
I create Photo.java like child of Users.java in relationship #ManytoOne
Here is my code :
Photo.java----
#Entity
public class Photo extends Model{
#Id
public Long id;
public String path;
#ManyToOne
#JoinColumn(name = "user_id")
public Users user;
}
Users.java-----
#Entity
public class Users extends Model{
#Id
public Long id;
#Constraints.Required
public String username;
#Constraints.Required
public String email;
#Constraints.Required
public String password;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
public List<Photo> photo = new ArrayList<Photo>();
public Users(){}
public Users(String username,String email,String password){
this.username=username;
this.email=email;
this.password=password;
}
}
Search.java -----
public static Result search(){
DynamicForm form = form().bindFromRequest();
String name = form.get("name");
Finder<Long, Users> find = new Finder<Long, Users>(Long.class, Users.class);
List<Users> users = find.where().like("username", '%'+ name +'%').findList();
if (form.get("name")=="" || users.isEmpty() || users==null){
return ok(search_again.render());
}
else{
return ok (search_result.render(users));
}
}
search_result.scala.html----
#(users : List[Users])
#main(nav= "search"){
<h3>Result</h3>
<input class="button" type="button" value="Back to Search">
<input class="button" type="button" value="Back to Home">
<p>Found #users.size() result(s) : </p>
<div class="sresult">
#for(user <- users){
<div id="sresult">
<div id="haha"><img src="#routes.Assets.at("upload/"+user.photo.path)"></div>
//Error here. Why "user.photo.path" not working ?
<p>
#user.username</a></br>
#user.password</a></br>
#user.email</a>
</p>
</div>
}
</div>
}
Why "user.photo.path" not working ? any ideal in my case ?