Accessing related entity of an entity stored in HttpSession - jpa

I have an image upload/store application in which I have a User entity having multiple related images(List<Image> images using OneToMany relationship). I am iterating images of the user in session using struts iterator tag in Home.jsp
<s:iterator value="#session['user'].images" status="itStatus">
<s:property value="imageid"/>
<s:property value="name"/>
<s:url action="GetImageAction" var="imgUrl">
<s:param name="imageId" value="imageid"></s:param>
</s:url>
<li>
<img src="<s:property value="#imgUrl"/>"/>
</li>
</s:iterator>
The upload form is on the same page so when the user logs in, he can see the images he has already uploaded & can also upload new images.
Here is my problem. When a new image is uploaded, the same page refreshes to show his images but the recently uploaded image does not get displayed(appears as broken) but I am able to see all previously uploaded images. This is because the imageId field of Image is having the value 0 in this case instead of the correct id. GetImageAction action sets the inputstream from the image using the param imageId
Here is the Image class:
#Entity(name="Images")
public class Image implements Serializable {
private long imageid;
private String name;
private byte[] image;
private static final long serialVersionUID = 1L;
public Image() {
super();
}
public Image(String name, byte[] image) {
super();
this.name = name;
this.image = image;
}
#Id
#GeneratedValue
#Column(name="Id")
public long getImageid() {
return this.imageid;
}
public void setImageid(long id) {
this.imageid = id;
}
...
}
Now I am guessing this is because the new Image object iterated is having the default long value 0 instead of the generated Id (I am able to access other fields' values like name). Why is this? Since the image is already persisted by the time the result is displayed, shouldn't the Id value be retrieved correctly? What am I doing wrong here?
Please help. I feel I may be missing something simple here but it just wouldn't get solved.
Edit:
UserAddImageAction
public class UserAddImageAction implements SessionAware {
private User user;
private Map session;
private File photo;
private String photoContentType;
private String photoFileName;
public String execute() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("StrTest1");
EntityManager em = emf.createEntityManager();
EntityTransaction etx = em.getTransaction();
try {
BufferedInputStream i = new BufferedInputStream(new FileInputStream(photo));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
while((c=i.read()) != -1) {
baos.write(c);
}
user = (User) session.get("user");
user.getImages().add(new Image(photoFileName, baos.toByteArray()));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
etx.begin();
em.merge(user);
etx.commit();
em.close();
emf.close();
session.put("user", user);
return "SUCCESS";
}
...

Related

java.sql.SQLSyntaxErrorException in mybatis

The phenomenon and background of the problem encountered
Problems encountered when configuring mybatis and writing tests, an error will be reported as soon as you click to run
problem related code,
#Test
public void findmany() throws IOException
{
InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession =sqlSessionFactory.openSession();
Map<String,Object> params = new HashMap<>();
params.put("name", "sam");
params.put("major", "");
List<Student> student=sqlSession.selectList("com.javaee.pojo.Student.findmany",params);
System.out.println(student);
Map<String,Object> params2 = new HashMap<>();
params2.put("name", "");
params2.put("major", "math");
student=sqlSession.selectList("com.javaee.pojo.Student.findmany",params2);
System.out.println(student);
Map<String,Object> params3 = new HashMap<>();
params3.put("name", "");
params3.put("major", "");
student=sqlSession.selectList("com.javaee.pojo.Student.findmany",params3);
System.out.println(student);
sqlSession.close();
}
mapper
<select id="findmany"
parameterType="map"
resultType="com.javaee.pojo.Student">
select * from students where name like concat('%',#{name},'%') major like concat('%',#{major},'%')
</select>
Student Class
public class Student {
private int id;
private String name;
private String major;
private String sno;
public String toString()
{
return "Student{"+"id="+id+",sno='"+sno+'\''+",name='"+name+'\''+",major='"+major+'\''+'}';
}
Running results and error content
enter image description here
Missing an AND in your select, try this way:
select * from students where name like concat('%',#{name},'%') AND major like concat('%',#{major},'%')

Spring-Boot RestController: Passing Id as String not working

I connected my Spring-Boot-Application to a MongoDB. The application is nothing serious, just for getting into working with spring and MongoDB.
The problem it, that my id is a String and I get an Internal Server Error, when I pass the id of a database entry, in order to get it byId...
This is my domain class:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Document(collection = "songinfo")
public class SongInfo {
#Id
private String id;
private int songId;
private String songName;
private String description;
}
The Controller-Method:
#RequiredArgsConstructor
#RestController
#RequestMapping("/songsinfo")
public class SongsInfoController {
private final SongInfoService songInfoService;
#GetMapping(value = "/{id}", headers = "Accept=application/json", produces =
{MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<SongInfo> getSongInfoById(#PathVariable(value = "id") String id) {
SongInfo songInfo = songInfoService.getSongInfoById(id);
if (songInfo == null)
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(songInfo, HttpStatus.OK);
}
The SongInfoServiceImpl:*
#Override
public SongInfo getSongInfoById(String id) {
return songInfoRepository.findById(id).orElseThrow(NotFoundException::new);
}
This is the SongsInfoRepository:
public interface SongInfoRepository extends MongoRepository<SongInfo, String> {
}
Getting all songinfos from the database is working fine:
But when is pass the id from one of these entries, I get this:
What is wrong here with my implementation?
You're throwing the exception in SongInfoServiceImpl which is not handled in your SongsInfoController Class.
Solution 1: Instead of throwing the exception return null.
SongInfoServiceImpl.java
#Override
public SongInfo getSongInfoById(String id) {
return songInfoRepository.findById(id).orElse(null);
}
Solution 2: Add try catch block
SongsInfoController.java
#RequiredArgsConstructor
#RestController
#RequestMapping("/songsinfo")
public class SongsInfoController {
private final SongInfoService songInfoService;
#GetMapping(value = "/{id}",
headers = "Accept=application/json",
produces = {MediaType.APPLICATION_JSON_VALUE}
)
public ResponseEntity<SongInfo> getSongInfoById(#PathVariable(value = "id") String id) {
SongInfo songInfo = null;
try {
songInfo = songInfoService.getSongInfoById(id);
} catch(Exception e) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(songInfo, HttpStatus.OK);
}
}
I think you need to divide two problem.
Check id parameter SongsInfoController
Inside controller check your parameter is valid through log or sysout
Check getSongInfoById method in SongInfoServiceImpl
Simply getSongInfoById(8752); is get error?
I want to add comment but my reputation is under 50.
If you comment above two solution check result, then I will add additional answer.

How to upload and retrieve file in mongodb in spring boot application without using GridFSTemplate?

I want to upload files and retrieve them from mongodb in spring boot application. But I don't want to use GridFSTemplate because my file size will not be greater than 16 MB. I am not choosing GridFSTemplate because none of the requirements mentioned in link https://docs.mongodb.com/manual/core/gridfs/#faq-developers-when-to-use-gridfs do not meet my requirements.
Is working with Document to save files and retrieve them using MongoTemplate a good approach?
MyDocument definition will look like
#Document
public class MyDocument {
#Id
private String id;
private String emailId;
private String docType;
#CreatedDate
private DateTime created;
#LastModifiedDate
private DateTime modified;
private File document;
}
Storing file
MyDocument document = new MyDocument();
document.setEmailId("abc#gmail.com");
document.setDocType("passport");
document.setDocument(file);
mongoTemplate.insert(document);
I want to store file along with some information like email. Later I will retrieve this file based on email parameter.
Please suggest if this approach is good or any other better solution is appreciated.
I could finally figure out the way to store files without using GridFS in mongodb. First thing you have to note that we have to store byte[] representation of file.
import org.bson.types.Binary;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
#Document
public class DemoDocument {
#Id
#Field
private String id;
#Field
private String emailId;
#Field
private String docType;
#Field
private Binary file;
}
Make sure your file object is org.bson.types.Binary.
Following is my controller code to save object in monogodb.
#PostMapping("/upload")
public String singleFileUpload(#RequestParam("file") MultipartFile multipart, #RequestParam("email") String email) {
try {
DemoDocument demoDocument = new DemoDocument();
demoDocument.setEmailId(email);
demoDocument.setDocType("pictures");
demoDocument.setDocument(new Binary(BsonBinarySubType.BINARY, multipart.getBytes()));
mongoTemplate.insert(demoDocument);
System.out.println(demoDocument);
} catch (Exception e) {
e.printStackTrace();
return "failure";
}
return "success";
}
You can retrieve this object from mongodb as following.
#PostMapping("/retrieve")
public String retrieveFile(#RequestParam("email") String email){
DemoDocument demoDocument = mongoTemplate.findOne(new BasicQuery("{emailId : \""+email+"\", docType : \"pictures\"}"), DemoDocument.class);
System.out.println(demoDocument);
Binary document = demoDocument.getDocument();
if(document != null) {
FileOutputStream fileOuputStream = null;
try {
fileOuputStream = new FileOutputStream(RETRIEVE_FOLDER + "prof_pic.jpg");
fileOuputStream.write(document.getData());
} catch (Exception e) {
e.printStackTrace();
return "failure";
} finally {
if (fileOuputStream != null) {
try {
fileOuputStream.close();
} catch (IOException e) {
e.printStackTrace();
return "failure";
}
}
}
}
return "success";
}
Please note this is just sample working code for understanding. It can be written in fully object oriented way keeping design principles in mind.

Spring MVC usage of form:radiobuttons to bind data (whole object not only one value)

I have a problem with sending data to backend by POST from my JSP using construction:
<form:radiobuttons path="pvClCategory" items="${categoryList}" itemLabel="clcaCategory"/>
After sumbit my Jboss (version 5) displays:
HTTP Status 400 - description: The request sent by the client was syntactically incorrect ().
I don't know how to see sent request. When I am using construction below everything works fine but I do not want to bind only one value from object, but whole object:
<form:radiobuttons path="pvClCategory.clcaCategory" items="${categoryList}" itemValue="clcaCategory" itemLabel="clcaCategory"/>
So, the first form construction (with binding whole object) cause me a problem. Form is initialised properly it means that radio options are correctly displayed and correct value is selected on jsp site. But problem appears when I want to submit the form, i receive error (HTTP Status 400 request sent by client was syntactically incorrect). Any idea why? What I am doing wrong?
My code:
I have one entity class Violation with field named pvClCategory type of ClCategory
#Entity
#Table(name="PV_VIOLATIONS")
public class Violation implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="VIOL_ID")
private Long id;
#ManyToOne
#JoinColumn(name="VIOL_CLCA_ID")
private ClCategory pvClCategory;
/* others fields and getters/setters */
}
My ClCategory entity class which is needed to bind it to Violation.pvClCategory field:
#Entity
#Table(name="PV_CL_CATEGORIES")
#Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
public class ClCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="CLCA_ID")
private long clcaId;
#Column(name="CLCA_CATEGORY")
private String clcaCategory;
#OneToMany(mappedBy="pvClCategory")
private List<Violation> pvViolations;
public ClCategory() {
}
public long getClcaId() {
return this.clcaId;
}
public void setClcaId(long clcaId) {
this.clcaId = clcaId;
}
public String getClcaCategory() {
return this.clcaCategory;
}
public void setClcaCategory(String clcaCategory) {
this.clcaCategory = clcaCategory;
}
public List<Violation> getPvViolations() {
return this.pvViolations;
}
public void setPvViolations(List<Violation> pvViolations) {
this.pvViolations = pvViolations;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (clcaId ^ (clcaId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ClCategory other = (ClCategory) obj;
if (clcaId != other.clcaId)
return false;
return true;
}
}
This Violation class is used in my form in commandName property as follows (file name: v.jsp):
<form:form action="../update" method="post" commandName="violation">
<form:radiobuttons path="pvClCategory" items="${categoryList}" itemLabel="clcaCategory"/>
<!-- other fields -->
<button type="submit" value="Apply Changes" class="button-default" >Apply</button>
</form:form>
My controller:
#Controller
#RequestMapping("/viol")
public class ViolationController {
#RequestMapping("edit/{violationId}")
public String edit(#PathVariable("violationId") long id, Map<String, Object> map) {
Violation violation = violationService.getViolation(id);
map.put("violation",violation);
map.put("categoryList", adminService.listCategories());
return "v";
}
}
As I understand in the construction form:radiobuttons path="" items="" the path is property for data binding so whole object from delivered list in items should be binded to it. I put in items List of my categories which are objects of type ClCategory. After submit error appears.
When i use form:radiobuttons path="pvClCategory.clcaCategory" items="${categoryList}" itemValue="clcaCategory" itemLabel="clcaCategory" to bind only String value from object in items (in both cases is used the same object list of type ClCategory) then the form is correctly submited but I do not want to bind only one value of objecte but whole object. Could you help me what am I doing wrong?

GWT RequestFactory: updates not propagated to cascaded object

I have an entity Company with a referenced object ItemVersion and I use JPA (eclipselink) as persistence layer. A code extract is given here:
#Entity
public class Company{
private String instance;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_item_version_id")
private ItemVersion itemVersion;
}
#Entity
public class ItemVersion{
private String comment;
...
}
I can create a Company object and persist it. I can also find the new object, update the attribute "instance" and persist it and everything works fine.
When I change the attribute "comment" of the referenced ItemVersion object, this change is not stored on the server side.
The create/update test code looks like:
final EventBus eventBus = new SimpleEventBus();
final AftdRequestFactory requestFactory = GWT.create(AftdRequestFactory.class);
requestFactory.initialize(eventBus);
final CompanyRequest request = requestFactory.companyRequest();
final CompanyProxy newCompany = request.create(CompanyProxy.class);
newCompany.setInstance("1");
ItemVersionProxy newVersion = request.create(ItemVersionProxy.class);
newVersion.setComment("first comment");
newCompany.setItemVersion(newVersion);
request.persist().using(newCompany).fire(new Receiver<Void>() {
#Override
public void onSuccess(Void arg0) {
final CompanyRequest request2 = requestFactory.companyRequest();
Request<CompanyProxy> p = request2.findCompany(1L).with("itemVersion");
p.to(new Receiver<CompanyProxy>() {
#Override
public void onSuccess(CompanyProxy response) {
final CompanyRequest request3 = requestFactory.companyRequest();
final CompanyProxy editableCompany2 = request3.edit(response);
editableCompany2.setInstance("2");
editableCompany2.getItemVersion().setVersionNumber(2);
request3.persist().using(editableCompany2).fire(new Receiver<Void>() {
#Override
public void onSuccess(Void arg0) {
// persist company version
System.out.println("company updated");
However, the update for "instance" and "comment" goes over the wire (checked wich wireshark between client and server), but in the persist method of Company, the referenced ItemVersion object and its "comment" attribute is not updated while "instance" is updated and therefore the old comment is stored.
The persist method of Company looks like:
public void persist() throws PersistenceException {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
try {
tx = em.getTransaction();
tx.begin();
Company existingEntity = findCompany(getId());
if (existingEntity == null) {
em.persist(this);
} else {
setId(existingEntity.getId());
em.merge(this);
}
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e;
}
The work around with a search and depending on the search result the em.persist or em.merge is necessary, because a simple persist does not store any updates.
You MUST use the open-session-in-view/session-per-request pattern (i.e. sharing the same EntityManager instance for the lifetime of the request) with RequestFactory; see https://code.google.com/p/google-web-toolkit/issues/detail?id=7827 for details.