Using logged in userid(foreign_key) for fillling out form in oneToMany mapping - spring

I am working on spring-mvc application which uses Spring Security to login and hibernate as the ORM tool. So, my project only has 2 tables, Table Person has OneToMany mapping with Table Notes. So, once the user is logged into the system, he/she should be able to add notes, but while adding I would like to also save the Person's id, which is why I have used to OneToMany mapping. But I don't know how to get user's id and put it in the form. Below is my code.
The error is
org.postgresql.util.PSQLException: ERROR: null value in column "personid" violates not-null constraint
Which is understandable, thats why I want to know how I can retreive the personid.
Person model :
#Entity
#Table(name="person")
public class Person implements UserDetails{
private static final GrantedAuthority USER_AUTH = new SimpleGrantedAuthority("ROLE_USER");
#Id
#Column(name="personid")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "person_seq_gen")
#SequenceGenerator(name = "person_seq_gen",sequenceName = "person_seq")
private int id;
#OneToMany(mappedBy = "person1")
private Set<Notes> notes1;
}
Note model :
#Entity
#Table(name="note")
public class Notes {
#Id
#Column(name="noteid")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "note_gen")
#SequenceGenerator(name = "note_gen",sequenceName = "note_seq")
private int noteId;
#ManyToOne
#JoinColumn(name = "personid")
private Person person1;
}
SQL :
CREATE TABLE public.person (
personid INTEGER NOT NULL,
firstname VARCHAR,
username VARCHAR,
password VARCHAR,
CONSTRAINT id PRIMARY KEY (personid)
);
CREATE TABLE public.note (
noteid INTEGER NOT NULL,
sectionid INTEGER,
canvasid INTEGER,
text VARCHAR,
notecolor VARCHAR,
noteheadline VARCHAR,
personid INTEGER NOT NULL,
CONSTRAINT noteid PRIMARY KEY (noteid)
);
ALTER TABLE public.note ADD CONSTRAINT user_note_fk
FOREIGN KEY (personid)
REFERENCES public.person (personid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
Person controller :
#Controller
public class PersonController {
private PersonService personService;
#Autowired(required=true)
#Qualifier(value="personService")
public void setPersonService(PersonService ps){
this.personService = ps;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String listPersons(Model model) {
model.addAttribute("person", new Person());
model.addAttribute("listPersons", this.personService.listPersons());
return "person";
}
//For add and update person both
#RequestMapping(value= "/person/add", method = RequestMethod.POST)
public String addPerson(#ModelAttribute("person") Person p){
//new person, add it
this.personService.addPerson(p);
return "redirect:/";
}
NoteController :
#Controller
public class NoteController {
private NotesService notesService;
#Autowired(required=true)
#Qualifier(value="notesService")
public void setNotesService(NotesService notesService){this.notesService=notesService;}
#RequestMapping(value = "/notes", method = RequestMethod.GET)
public String listNotes(Model model) {
model.addAttribute("notes", new Notes());
model.addAttribute("listnotes", this.notesService.listNotes());
return "notes";
}
#RequestMapping(value= "/note/add", method = RequestMethod.GET)
public String addNote(#ModelAttribute("notes") Notes p){
this.notesService.addNote(p);
return "redirect:/";
}
}
Note.jsp (here is where I add notes.)
<c:url var="addAction" value="/note/add" ></c:url>
<form:form action="${addAction}" commandName="notes">
<table>
<c:if test="${!empty notes.note}">
<tr>
<td>
<form:label path="noteid">
<spring:message text="noteid"/>
</form:label>
</td>
<td>
<form:input path="noteid" readonly="true" size="8" disabled="true" />
<form:hidden path="noteid" />
</td>
</tr>
</c:if>
<tr>
<td>
<form:label path="note">
<spring:message text="note"/>
</form:label>
</td>
<td>
<form:input path="note" />
</td>
</tr>
<tr>
<td>
<form:label path="notetag">
<spring:message text="notetag"/>
</form:label>
</td>
<td>
<form:input path="notetag" />
</td>
</tr>
<tr>
<td>
<form:label path="notecolor">
<spring:message text="notecolor"/>
</form:label>
</td>
<td>
<form:input path="notecolor" />
</td>
</tr>
<tr>
<td>
<form:label path="canvasid">
<spring:message text="canvasid"/>
</form:label>
</td>
<td>
<form:input path="canvasid" />
</td>
</tr>
<tr>
<td>
<form:label path="sectionid">
<spring:message text="sectionid"/>
</form:label>
</td>
<td>
<form:input path="sectionid" />
</td>
</tr>
<tr>
<td colspan="2">
<c:if test="${!empty notes.note}">
<input type="submit"
value="<spring:message text="Edit note"/>" />
</c:if>
<c:if test="${empty notes.note}">
<input type="submit"
value="<spring:message text="Add note"/>" />
</c:if>
</td>
</tr>
</table>
</form:form>

Not sure if I understood you correctly but when there is a logged in user (Principal) in a thread then you can just use SecurityContextHolder.getContext().getAuthentication().getPrincipal() to get the Principal or just inject it using #AuthenticationPrincipal or just make sure your Person implements Principal interface and inject it directly (I assume a Person is a User and a User is a Principal) to get the person.id.
In /note/add try like this:
public String addNote(#ModelAttribute("notes") Notes p, #AuthenticationPrincipal Person person)) {
p.setPerson1(person);
this.notesService.addNote(p);
return "redirect:/";
}
If you want to avoid setting it manually consider usage of AuditorAware and Auditable like here:
http://www.springbyexample.org/examples/spring-data-jpa-auditing-code-example.html

Related

"org.hibernate.PersistentObjectException: detached entity" followed by application crash

I am trying persist this entity:
#Entity
public class Produto extends Model {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
...
#OneToMany
#Fetch(FetchMode.SELECT)
#Cascade(CascadeType.ALL)
private List<Imagem> thumbnails;
...
}
through this form:
<table>
<tbody><tr>
<td>
<button type="button" onclick="add_single_imagem();" style="display: block;">
<img class="thumbnail" src="/images/icon_add_imagem.png" alt="adicionar icone">
<input type="file" accept="image/jpeg" class="image-uploader" id="thumbnails" style="display: none;" onchange="image_upload(this);" data-target="thumbnails" data-url="/imagem/upload" data-path="/imagem/download">
</button>
</td>
<td>
<div class="gallery" id="gallery">
<input type="hidden" name="thumbnails" value="3"><img class="thumbnail" id="image_3" src="/imagem/download/3"></div>
</td>
</tr>
</tbody></table>
which follow this "route":
controller
#RequestMapping(value = "/insert", method=RequestMethod.POST)
#ResponseBody
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
public void insert(#Valid E object, BindingResult result) {
serv.insert(object);
}
service
public void insert(E object) {
dao.insert(object);
}
dao
public void insert(E object) {
EntityManager entityManager = getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(object);
entityManager.getTransaction().commit();
entityManager.close();
}
PropertyEditor
public class ImagemEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) {
if (!text.equals("")) {
Integer id = Integer.parseInt(text);
ImagemService serv = new ImagemService();
org.loja.AppContextHolder.getContext().getAutowireCapableBeanFactory().autowireBean(serv);
Imagem imagem = serv.findBy("id", id);
setValue(imagem);
} else {
setValue(null);
}
}
}
But I am getting this error:
org.hibernate.PersistentObjectException: detached entity passed to persist: org.loja.model.imagem.Imagem
and when I try quit the application (with ctrl-c, I am running it with spring-boot), it crashes, stuck with this message:
2019-11-18 19:55:46.244 INFO 134572 --- [ Thread-3] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
until I kill the process.
Anyone can give a hint of what's wrong here?
I managed to solve this issue changing the attribute configuration to that:
#OneToMany(fetch = FetchType.EAGER)
private Set<Imagem> thumbnails;
and with this html/thymeleaf code:
<table>
<tr>
<td>
<button type="button" onclick="add_single_imagem();" th:style="${command.icone}? 'display: none;' : 'display: block;'">
<img class="thumbnail" th:src="#{/images/icon_add_imagem.png}" alt="adicionar icone"/>
<input type="file" accept="image/jpeg" class="image-uploader" id="thumbnails" style="display: none;" th:attr="data-target=${'thumbnails'}, data-url=#{/imagem/upload}, data-path=#{/imagem/download}" onchange="image_upload(this);"/>
</button>
</td>
<td>
<div class="gallery" id="gallery">
<th:block th:each="img,stat : ${command.thumbnails}">
<input type="hidden" th:field="*{thumbnails}" th:value="${img.id}"/>
<img class="thumbnail" th:id="${'image_'+img.id}" th:src="#{/imagem/download/__${img.id}__}" th:alt="${command.nome}">
</th:block>
</div>
</td>
</tr>
</table>
Now this attribute is persisted alongside the entity without problems.

Spring boot+Web mvc+JPA using CrudRepository giving issue on insert of a row using save method throwing EntityExistsException

Among CRUD operation Create is giving error of "A different object with the same identifier value was already associated with the session" Rest all (Read, Update and Delete) is working fine.
Im using oracle sql as database and there is one more entity of product with many to one mapping with categories class.
EntityClass
#Entity
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
public Categories() {
super();
}
public Categories(Integer id,String name) {
this.id=id;
this.name=name;
}
public Categories(String name) {
this.name=name;
}
//with setters and getters
}
JSP page
<body onload="document.getElementById('name').disabled = true;document.getElementById('hidden').disabled = true;">
<div align="center">
<h4>Add or Modify or Delete Categories</h4>
<form:form method="POST" action="/categories" modelAttribute="categories">
<table>
<tr>
<td><form:label path="name">Name</form:label></td>
<td>
<form:select path="name">
<form:option value="NONE" label="Select" />
<form:options items="${categoriesList}" />
</form:select>
</td>
</tr>
<tr>
<td>Operations</td>
<td>
<input type="radio" name="Ops" value="Add" checked="checked" onclick="document.getElementById('name').disabled = true; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Add</input><br/>
<input type="radio" name="Ops" value="Modify" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Modify</input><br/>
<input type="radio" name="Ops" value="Delete" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = true;document.getElementById('hidden').disabled = false;">Delete</input><br/>
</td>
</tr>
<tr>
<td>Name</td>
<td><input type="text" name="newName" id="newName"/>
<input type="hidden" id="hidden" name="newName" value="dummy"/>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</div>
</body>
Controller Class
#Controller
public class CategoriesController {
#Autowired
private CategoriesService cservice;
#RequestMapping(value = "/categories", method = RequestMethod.GET)
public ModelAndView categories() {
// view name model
ModelAndView modelAndView = new ModelAndView("categories", "categories", new Categories());
return modelAndView;
}
#RequestMapping(value = "/categories", method = RequestMethod.POST)
public String opsOnCategories(#ModelAttribute("categories") Categories cat,#RequestParam("Ops") String ops,#RequestParam("newName") String name)
{
if(ops.equals("Modify"))
{
cservice.modifyCategory(new Categories(Integer.parseInt(cat.getName()), name));
}else if(ops.equals("Add"))
{
cservice.addCategory(new Categories(name));
}else
{
cservice.deleteCategory(Integer.parseInt(cat.getName()));
}
return "categories";
}
#ModelAttribute("categoriesList")
public Map<String, String> getCategoryList() {
Map<String, String> categoriesList = new HashMap<String, String>();
List<Categories> ls=cservice.getAll();
for(int i=0;i<ls.size();i++)
{
categoriesList.put(ls.get(i).getId().toString(), ls.get(i).getName());
}
return categoriesList;
}
}
Can anyone please help on this.
Previous one due to which there was error
insert into CATEGORIES(ID,NAME) values (1,'Mobile');
insert into CATEGORIES(ID,NAME) values (2,'Laptop');
**Changes made to remove error*
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Mobile');
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Laptop');
My initial guess is that there something wrong with #Id #GeneratedValue with Oracle Database specifically.
There are couple of things that you can do:
1- Try to connect to any other Database type just to test the functionality - so that you can rule out what doesn't matter
2- Try to use the #org.springframework.data.annotation.Id alongside with the #Id of javax persistence
Something that look like this
#Id
#org.springframework.data.annotation.Id
private Integer id;
3- Create a class that Generates random Integer Ids and refer to it using the annotations (#GenericGenerator & #GeneratedValue)

Spring-Hibernate insertion Error with Column 'unit_id' cannot be null Exception

I am developing a small Spring and hibernate base application in java, and my appication has a one to many relationship with Employee and Unit, Employee has a one unit, Unit has a many Employee.
in this small application genarate error like this `
I was hard code data to Unit schema table, i populate unit combobox filled in jsp its works, but inside the #controller unit has a null data.
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Column 'unit_id' cannot be null
if allow to null value to unit_id other data inserted with out insert unit_id
here my Entity class
#Entity
#Table(name = "employee")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "epf")
private int epf;
#Column(name = "fname")
private String fname;
#Column(name = "lname")
private String lname;
#Column(name = "email")
private String email;
#JoinColumn(name = "unit_id", referencedColumnName = "id")
#ManyToOne//(optional = false)
private Unit unit;
#Entity
#Table(name = "unit")
public class Unit implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
My controller Class
#Autowired
private EmployeeService employeeService;
private DesignationService designationService;
#RequestMapping({"/index", "/"})
public String setupForm(Map<String, Object> map){
Employee student = new Employee();
map.put("employee", student);
map.put("employeeList", employeeService.getAllEmployee());
map.put("unitList", employeeService.getAllUnitList());
return "employee";
}
#RequestMapping(value="/employee.do", method=RequestMethod.POST)
public ModelAndView doActions(#ModelAttribute Employee emp, BindingResult result, #RequestParam String action, Map<String, Object> map){
ModelAndView modelAndView = new ModelAndView("employee");
Employee employeetResult = new Employee();
switch(action.toLowerCase()){ //only in Java7 can put String in switch
case "add":
employeeService.addEmployee(emp);
employeetResult = emp;
break;
case "edit":
employeeService.updateEmployee(emp);
employeetResult = emp;
break;
case "delete":
employeeService.deleteEmployee(emp.getId());
employeetResult = new Employee();
break;
case "search":
Employee searchedStudent = employeeService.getEmployee(emp.getId());
employeetResult = searchedStudent!=null ? searchedStudent : new Employee();
break;
}
map.put("employee", employeetResult);
map.put("employeeList", employeeService.getAllEmployee());
return modelAndView;
}
My JSP
<form:form action="employee.do" method="POST" commandName="employee">
<table width="341" border="0">
<tr>
<td width="154"> </td>
<td width="21"> </td>
<td width="152"> </td>
</tr>
<tr>
<td><spring:message code="employee.id"/></td>
<td> </td>
<td><form:input path="epf" /></td>
</tr>
<tr>
<td><spring:message code="employee.epf"/></td>
<td> </td>
<td><form:input path="epf" /></td>
</tr>
<tr>
<td><spring:message code="employee.fname"/></td>
<td> </td>
<td><form:input path="fname"/></td>
</tr>
<tr>
<td><spring:message code="employee.lname"/></td>
<td> </td>
<td><form:input path="lname" /></td>
</tr>
<tr>
<td><spring:message code="employee.email"/></td>
<td> </td>
<td><form:input path="email" /></td>
</tr>
<tr>
<td><spring:message code="employee.unit"/></td>
<td> </td>
<!-- Unit Combo filling --><td>
<form:select path="unit" multiple="false" size="1">
<form:options items="${unitList}" itemValue="id" itemLabel="name"/>
</form:select>
<!-- Unit Combo filling end --></td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="action" value="Add" />
<input type="submit" name="action" value="Edit" />
<input type="submit" name="action" value="Delete" />
<input type="submit" name="action" value="Search" />
</td>
</tr>
</table>
</form:form>
My DAO Class
> #Repository public class EmployeeDaoImp implements EmployeeDao {
>
> #Autowired private SessionFactory sessionfactory;
> public void addEmployee(Employee emp) { sessionfactory.getCurrentSession().save(emp);
>
> }
>
> public void updateEmployee(Employee emp) {
> sessionfactory.getCurrentSession().update(emp);
>
> }
>
> public void deleteEmployee(int id) {
> sessionfactory.getCurrentSession().delete(getEmployee(id)); }
>
> Employee public Employee getEmployee(int empId) {
> return (Employee) sessionfactory.getCurrentSession().get(Employee.class,empId); }
>
> public List getAllEmployee() {
> return sessionfactory.getCurrentSession().createQuery("from Employee").list(); }
The id is primary key in the DB. You are save an object without giving it's value. So either make it auto increment in table or generate it's value using hibernate.

How to populate a form:select and select a default value?

I have an edit user form which has textfields(username, lastname..) and a select of countries. I'm having problems with this select because i don't know the better way to populate it. I've tried populating with jquery with success but i cannot select a default value through commandName.
<form:form method="POST" commandName="user" action="registerUser.html">
<form:errors path="*" cssClass="errorblock" element="div" />
<spring:message code="app.user.username"/><form:input path="username" /><form:errors path="username" cssClass="error" /><br/>
<spring:message code="app.user.firstname"/> <form:input type="text" path="firstName" /> <form:errors path="firstName" cssClass="error"/><br/>
<spring:message code="app.user.password"/> <form:input type="password" path="password" /><form:errors path="password" cssClass="error"/><br/>
<spring:message code="app.user.repassword"/> <form:input type="password" path="confirmPassword" /><form:errors path="confirmPassword" cssClass="error"/><br/>
<spring:message code="app.user.email"/> <form:input type="text" path="email" /><form:errors path="email" cssClass="error"/><br/>
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
<input type="submit" value="Enviar" />
</form:form>
I've take a look to this tutorial, so i've tried with a map but i don't know how to return the data to be accesible in the jsp because in the tutorial uses a SimpleFormController but i wouldn't like to code a SimpleFormController for each form. This is my controller to return the view of the form and i have another to catch the submit.
#RequestMapping(method=RequestMethod.GET, value="/editUserForm")
public String recordUserRequestHandler(ModelMap model) throws Exception {
model.addAttribute("user", new User());
Map<String, Map<String, String>> referenceData = new HashMap<String, Map<String, String>>();
Map<String, String> country = new LinkedHashMap<String, String>();
country.put("US", "United Stated");
country.put("CHINA", "China");
country.put("SG", "Singapore");
country.put("MY", "Malaysia");
referenceData.put("countryList", country);
return "EditUserForm";
}
is it possible to pass the referenceData to the jsp to be accessed by the form:select?
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
Also you don't need to use hashmap for selects. Personally I use simple List with beans which holds my select options.
public class ListOption {
private String id;
private String name;
public ListOption(String id, String name) {
this.id = id;
this.name = name;
}
public ListOption() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
in your controller
List<ListOption> selectOptions = new List<ListOption>();
// add Your options
selectOptions.add(new ListOption("id","value");
then put isoCode object into your model with desired (selected) value then spring will manage to mark the value as selected.
in your jsp
<form:select path="isoCode" items="${countryList}" itemValue="id" itemLabel="name"/>

Spring retrieving one object

On my page I would like to get only one user details. The problem being that I'm having problems with displaying the details of the user on the page. The object that I'm trying to retrieve has a onetomany relationship with another class. So I would like to list the associated objects as well.
Model
#Entity
#Table(name = "user")
#Component
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "user_id")
private Integer userId;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="setter")
private Set<Module> sModule = new HashSet<Module>();
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="checker")
private Set<Module> cModule = new HashSet<Module>();
Controller
#RequestMapping(value = "/main/user/testing", method = RequestMethod.GET)
public String getRecords(#RequestParam("userId") Integer userId, ModelMap
model) {
if(userId !=null)
{
UserEntity user = userService.getUserByID(userId);
model.addAttribute("user", user);
}
return "/main/user/testing";
}
Jsp page
<table>
<tr>
<th>User Id</th>
<th>Name</th>
<th>Module Code</th>
<th>Module Name</th>
</tr>
<c:forEach items="${user}" var="obj" >
<c:forEach items="${obj.sModule}" var="module" >
<tr>
<td><c:out value="${obj.userId}" escapeXml="true" /></td>
<td><c:out value="${obj.name}" escapeXml="true" /></td>
<td><c:out value="${module.moduleCode}" escapeXml="true" /></td>
<td><c:out value="${module.moduleName}" escapeXml="true" /></td>
</tr>
</c:forEach>
</c:forEach>
</table>
Using the controller code, when I try to access the page. The user details are not included. So I wanted to know if there was a way I would be able to render the object for just one user instead of a list of users.
Why do you use <c:forEach items="${user}" var="obj" >? It looks that UserEntity is an object but not List. So, remove <c:forEach items="${user}" var="obj" > and try
<c:out value="${user.userId}" escapeXml="true" />

Resources