Sunday, 21 September 2014

ZK upload PDF to server and show in the screen using MVVM–Part 2

In the Part 1, we have seen how to upload the PDF File and show in the same desktop. This example will show you how to show the PDF in the separate tab in the same browser window.


ZK Version : ZK 7.0.3
Project Name : zk7example6

Step 1:
Follow
this post, to create ZK 7 Maven Project.

image
When you create ZK Maven Project, you can see by default index.zul and MyViewModel.Java will be created. We will modify this zul and VM for our example.


Step 2:
Let us modify the index.zul and MyViewModel.java to accept the PDF File from the user and stored in the server directory. And also You can see that there are two buttons to show the PDF ; one is to show PDF File on the same desktop, and the other is to show the same PDF in the separate tab in the same browser.

Index.zul

<zk>
<window apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm')@init('ZKExample6.MyViewModel')">
<label value="You are using: ${desktop.webApp.version}" />
<separator></separator>
<label
value="Example for File upload to the server and display it" />
<separator></separator>
<hbox>
<label value="Upload any PDF File" />
<button label="Upload" upload="true"
onUpload="@command('onUploadPDF',upEvent=event)">
</button>
</hbox>
<button label="Show PDF Option 1" visible="@load(vm.fileuploaded)"
onClick="@command('showPDFOption1')">
</button>
<button label="Show PDF Option 2" visible="@load(vm.fileuploaded)"
onClick="@command('showPDFOption2')">
</button>
</window>
</zk>

ViewModel for our Index.zul file.


package ZKExample6;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;

import org.zkoss.bind.BindContext;
import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.io.Files;
import org.zkoss.util.media.AMedia;
import org.zkoss.util.media.Media;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Iframe;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

public class MyViewModel {

private String filePath;
private boolean fileuploaded = false;
AMedia fileContent;

@Wire("#test")
private Window win;

public AMedia getFileContent() {
return fileContent;
}

public void setFileContent(AMedia fileContent) {
this.fileContent = fileContent;
}

public boolean isFileuploaded() {
return fileuploaded;
}

public void setFileuploaded(boolean fileuploaded) {
this.fileuploaded = fileuploaded;
}

@AfterCompose
public void initSetup(@ContextParam(ContextType.VIEW) Component view) {
Selectors.wireComponents(view, this, false);

}

@Command
@NotifyChange("fileuploaded")
public void onUploadPDF(
@ContextParam(ContextType.BIND_CONTEXT) BindContext ctx)
throws IOException {

UploadEvent upEvent = null;
Object objUploadEvent = ctx.getTriggerEvent();
if (objUploadEvent != null && (objUploadEvent instanceof UploadEvent)) {
upEvent = (UploadEvent) objUploadEvent;
}
if (upEvent != null) {
Media media = upEvent.getMedia();
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month = now.get(Calendar.MONTH); // Note: zero based!
int day = now.get(Calendar.DAY_OF_MONTH);
filePath = Executions.getCurrent().getDesktop().getWebApp()
.getRealPath("/");
String yearPath = "\\" + "PDFs" + "\\" + year + "\\" + month + "\\"
+ day + "\\";
filePath = filePath + yearPath;
File baseDir = new File(filePath);
if (!baseDir.exists()) {
baseDir.mkdirs();
}
Files.copy(new File(filePath + media.getName()),
media.getStreamData());
Messagebox.show("File Sucessfully uploaded in the path [ ."
+ filePath + " ]");
fileuploaded = true;
filePath = filePath + media.getName();
}
}

@Command
public void showPDFOption1() throws IOException {
Window win = (Window) Executions.createComponents(
"zkpdfviewer.zul", null, null);
Iframe frame = (Iframe) win.getFellow("reportframe");
File f = new File(this.filePath);
byte[] buffer = new byte[(int) f.length()];
FileInputStream fs = new FileInputStream(f);
fs.read(buffer);
fs.close();

ByteArrayInputStream is = new ByteArrayInputStream(buffer);
AMedia amedia = new AMedia(filePath, "pdf", "application/pdf", is);
frame.setContent(amedia);

}

@Command
public void showPDFOption2() throws IOException {
String URL;
URL = "zkpdfviewer.zul?filepath=";
URL = URL + EncryptionUtil.encode(filePath);
Executions.getCurrent().sendRedirect(URL, "_blank");

}
}

Step 3:
As you can see, we have two buttons to show the uploaded PDF. One option is normal to open on the same screen, and the other one is open the pdf in the separate tab.In the both option, we have used separate ZUL File to view the PDF. Here is the zul file and its corresponding VM.


 <window id="pdfwindow" width="100%" height="100%" title="PDF-Viewer"
border="normal" minimizable="false" mode="modal" maximizable="false"
sclass="mymodal" closable="true" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('ZKExample6.ZKPDFViewerVM')">
<iframe height="100%" width="100%" id="reportframe"></iframe>
</window>

View Model

package ZKExample6;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;

import org.zkoss.bind.annotation.AfterCompose;
import org.zkoss.bind.annotation.ContextParam;
import org.zkoss.bind.annotation.ContextType;
import org.zkoss.bind.annotation.QueryParam;
import org.zkoss.util.media.AMedia;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.select.Selectors;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Iframe;

public class ZKPDFViewerVM {

@Wire("#reportframe")
private Iframe iframe;

@AfterCompose
public void initSetup(@ContextParam(ContextType.VIEW) Component view,
@QueryParam("filepath") String filePath) throws Exception {
Selectors.wireComponents(view, this, false);
if (filePath==null)
filePath = "";
if (filePath.isEmpty()==false) {
filePath = EncryptionUtil.decode(filePath);
File f = new File(filePath);
byte[] buffer = new byte[(int) f.length()];
FileInputStream fs = new FileInputStream(f);
fs.read(buffer);
fs.close();
ByteArrayInputStream is = new ByteArrayInputStream(buffer);
AMedia amedia = new AMedia(filePath, "pdf", "application/pdf", is);
iframe.setContent(amedia);
}
}
}

For the second option, actually we are passing the PDF File path from the server as URL and we received this in the VM and then showing the IFrame. For security reasons,  We can encode the URL and then we can decode the URL. That's what the additional static class EncryptionUtil.java does. Here is the code.


package ZKExample6;

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.apache.commons.codec.binary.Base64;

public class EncryptionUtil {

private static final byte[] SALT = { (byte) 0x21, (byte) 0x21, (byte) 0xF0,
(byte) 0x55, (byte) 0xC3, (byte) 0x9F, (byte) 0x5A, (byte) 0x75 };

private final static int ITERATION_COUNT = 31;

private EncryptionUtil() {
}

public static String encode(String input) {
if (input == null) {
throw new IllegalArgumentException();
}
try {

KeySpec keySpec = new PBEKeySpec(null, SALT, ITERATION_COUNT);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(SALT,
ITERATION_COUNT);

SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
.generateSecret(keySpec);

Cipher ecipher = Cipher.getInstance(key.getAlgorithm());
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

byte[] enc = ecipher.doFinal(input.getBytes());

String res = new String(Base64.encodeBase64(enc));
// escapes for url
res = res.replace('+', '-').replace('/', '_').replace("%", "%25")
.replace("\n", "%0A");

return res;

} catch (Exception e) {
}

return "";

}

public static String decode(String token) {
if (token == null) {
return null;
}
try {

String input = token.replace("%0A", "\n").replace("%25", "%")
.replace('_', '/').replace('-', '+');

byte[] dec = Base64.decodeBase64(input.getBytes());

KeySpec keySpec = new PBEKeySpec(null, SALT, ITERATION_COUNT);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(SALT,
ITERATION_COUNT);

SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES")
.generateSecret(keySpec);

Cipher dcipher = Cipher.getInstance(key.getAlgorithm());
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

byte[] decoded = dcipher.doFinal(dec);

String result = new String(decoded);
return result;

} catch (Exception e) {
// use logger in production code
e.printStackTrace();
}

return null;
}

}



Here is the complete Project Structure

image
|
Now you can run the index.zul file and you check the output by clicking the two buttons.
You can download the source code
here.

3 comments:

  1. it´s a good tutorial can you post a tutorial to checkbox please good vibes

    ReplyDelete
  2. can you explain this to support another format

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete