Hello dear commmunity.
I have a problem i cannot seem to solve.
Let me explain what i try to do.
I have a simple JSF-Site with a select file dialog and a submit button.
When a user selects a file and clicks the submit button this file shall be send to a servlet on my server, where it is saved locally and a db entry shall be created that points to the location of the file.
Sounds simple right?
Here is my solution so far:
The JavaScript:
function postUploadedFile() {
var servlet = "UploadImageToServer";
var inputElement = document.getElementById('filedataDecoded');
var fileTypeElement = document.getElementById('filedataType');
var encodedFile = inputElement.textContent;
var fileType = fileTypeElement.textContent;
inputElement.textContent = "";
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "http://localhost:8080/TestJSF/" + servlet + "?fileType="+fileType , true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function () {
if ((xmlhttp.readyState == 4)) {
// handle callback
console.log("done");
}
}
xmlhttp.send(encodedFile);
console.log();
}
My Servlet:
public class UploadImageToServer extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(UploadImageToServer.class);
private String dbUser = "xxxx";
private String dbPw = "xxxx";
public UploadImageToServer() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PreparedStatement stm = null;
Connection con = null;
InputStream fileDataStream = request.getInputStream();
int fileContentLength = request.getContentLength();
String fileType = (request.getParameter("fileType")).split("\\.")[1];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] fileDataBytes64 = new byte[fileContentLength];
byte[] bufferTemp = new byte[1024];
int nRead;
while ((nRead = fileDataStream.read(bufferTemp, 0, bufferTemp.length)) != -1) {
buffer.write(bufferTemp, 0, nRead);
}
buffer.flush();
String tempString = buffer.toString();
String base64String = tempString.split("base64,")[1];
System.out.println("test");
Double newRandom = (double) -1;
while(newRandom < 5000 || newRandom > 1000000) {
newRandom = Math.random() * 10000;
}
String valueOf = String.valueOf((newRandom));
String fileName = (valueOf.split("\\."))[0] + "." + fileType;
File tempFile = new File("C:\\storage\\" + fileName);
byte[] fileDataDecoded = Base64.decodeBase64(base64String);
tempFile.getParentFile().mkdir();
tempFile.createNewFile();
FileOutputStream foS = new FileOutputStream(tempFile);
foS.write(fileDataDecoded);
foS.close();
String driver = PossibleDbDriver.MYSQL.getIdentifier();
try {
Class.forName(driver);
} catch (ClassNotFoundException e2) {
logger.error("Error - no valid Driver-Class specified - [" + driver + "]");
logger.error("Message - [" + e2.getMessage() + "]");
}
String dbURL = "jdbc:mysql://localhost:3306/imagetest";
try {
con = (Connection) DriverManager.getConnection(dbURL,dbUser,dbPw);
stm = con.prepareStatement("INSERT INTO images (image_name,image_path,image_likes,image_dislikes,image_timestamp) VALUES(?,?,?,?,?)");
stm.setString(1, tempFile.getName());
stm.setString(2, tempFile.getPath());
stm.setDouble(3, 0);
stm.setDouble(4, 0);
stm.setTimestamp(5, new Timestamp(GregorianCalendar.getInstance().getTimeInMillis()));
stm.execute();
} catch (SQLException e) {
logger.error("Error - Connection could not be established.");
logger.error("Message - [" + e.getMessage() + "]");
}
}
}
Servlet Mapping:
<servlet>
<description></description>
<display-name>UploadImageToServer</display-name>
<servlet-name>UploadImageToServer</servlet-name>
<servlet-class>mk.imageboard.servlets.UploadImageToServer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadImageToServer</servlet-name>
<url-pattern>/UploadImageToServer</url-pattern>
</servlet-mapping>
The file data comes from another script that reads it as a Base64-String and writes it to the TextArea-Element 'filedataDecoded' (Just to clarify this).
The Application Server is Tomcat 6.0.36 and the JSF implementation is MyFaces 2.1.13.
Everything runs on the same machine(my computer).
Now to my actual problem...
When i let Tomcat run in normal mode and access my site and try to upload a file, the XmlHttpRequest is not send. However when i do the same thing with opened JavaScript Console in Chrome and set breakpoints to:
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "http://localhost:8080/TestJSF/" + servlet + "?fileType="+fileType , true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function () {
if ((xmlhttp.readyState == 4)) {
// handle callback
console.log("done");
}
}
xmlhttp.send(encodedFile);
and step through the script, the request is send and the servlet works fine.
I searched stackoverflow for a solution but couldn't find any. Same with the internet. It's such a weird error and i can't understand why it does not work.
If someone could help me out i would really appreciate it.
Thanks in advance
Chris
Try to use relative path instead of absolute path.
xmlhttp.open("POST", "TestJSF/" + servlet + "?fileType="+fileType , true);
or
xmlhttp.open("POST", "" + servlet + "?fileType="+fileType , true);
Update:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
xmlhttp.open("GET", "TestJSF/" + servlet + "?fileType="+fileType , true);
or
xmlhttp.open("GET", "" + servlet + "?fileType="+fileType , true);
Ok. I think I have found the solution or the cause of the problem.
Somehow the <h:form>...</h:form> surrounding the actual submit button firing the javascript prevented the sending of the request, but as to why it does, I don't know. I deleted the form and it works now correctly.
Does someone have a guess on why this caused the problem? I would really like to know.
But thanks anyway guys. Have a happy new year :)
With kind regards
Chris
EDIT: The missing HTML-Snipped of my site. Sorry I should have added it, my bad!
<ui:define name="content">
<!-- Testbereich -->
<fieldset>
<input type="file" id="file" name="file" enctype="multipart/form-data" onchange=""/>
<input type="submit" value="Verschluesseln" onclick="loadUploadedFile();"/>
</fieldset>
<fieldset>
<div> Uploaddaten nicht verschluesselt:</div>
<h:inputTextarea id="filedataType" styleClass="textareaOutput" disabled="true"/>
<h:inputTextarea id="filedataDecoded" styleClass="textareaOutput" disabled="true"/>
</fieldset>
<!-- <h:form id="uploadForm"> -->
<fieldset>
<input type="submit" onclick="postUploadedFile();"/>
</fieldset>
<!-- </h:form> -->
</ui:define>
To clarify loadUploadedFile() is the javascript that reads the file and returns the Base64 String.
Related
So I am using Java for my Server and Angular for the Client. I am currently working on a feature where you can select multiple files from a table and when you press on download, it generates a zip file and downloads it to your browser. As of right now, the server now creates the zip file and I can access it in the server files. All that is left to do is to make it download on the client's browser. (the zip file is deleted after the client downloads it)
After doing some research, I found out that you can use a fileOutputStream to do this. I also saw some tools like retrofit... I am using REST and this is what my code looks like. How would I achieve my goal as simply as possible?
Angular
httpGetDownloadZip(target: string[]): Observable<ServerAnswer> {
const params = new HttpParams().set('target', String(target)).set('numberOfFiles', String(target.length));
const headers = new HttpHeaders().set('token', this.tokenService.getStorageToken());
const options = {
headers,
params,
};
return this.http
.get<ServerAnswer>(this.BASE_URL + '/files/downloadZip', options)
.pipe(catchError(this.handleError<ServerAnswer>('httpGetZip')));
}
Java zipping method
public void getDownloadZip(String[] files, String folderName) throws IOException {
[...] // The method is huge but basically I generate a folder called "Download/" in the server
// Zipping the "Download/" folder
ZipUtil.pack(new File("Download"), new File("selected-files.zip"));
// what do I return ???
return;
}
Java context
server.createContext("/files/downloadZip", new HttpHandler() {
#Override
public void handle(HttpExchange exchange) throws IOException {
if (!handleTokenPreflight(exchange)) { return; }
System.out.println(exchange.getRequestURI());
Map<String, String> queryParam = parseQueryParam(exchange.getRequestURI().getQuery());
String authToken = exchange.getRequestHeaders().getFirst("token");
String target = queryParam.get("target") + ",";
String[] files = new String[Integer.parseInt(queryParam.get("numberOfFiles"))];
[...] // I process the data in this entire method and send it to the previous method that creates a zip
Controller.getDownloadZip(files, folderName);
// what do I return to download the file on the client's browser ????
return;
}
});
A possible approach to successfully download your zip file can be the described in the following paragraphs.
First, consider returning a reference to the zip file obtained as the compression result in your downloadZip method:
public File getDownloadZip(String[] files, String folderName) throws IOException {
[...] // The method is huge but basically I generate a folder called "Download/" in the server
// Zipping the "Download/" folder
File selectedFilesZipFile = new File("selected-files.zip")
ZipUtil.pack(new File("Download"), selectedFilesZipFile);
// return the zipped file obtained as result of the previous operation
return selectedFilesZipFile;
}
Now, modify your HttpHandler to perform the download:
server.createContext("/files/downloadZip", new HttpHandler() {
#Override
public void handle(HttpExchange exchange) throws IOException {
if (!handleTokenPreflight(exchange)) { return; }
System.out.println(exchange.getRequestURI());
Map<String, String> queryParam = parseQueryParam(exchange.getRequestURI().getQuery());
String authToken = exchange.getRequestHeaders().getFirst("token");
String target = queryParam.get("target") + ",";
String[] files = new String[Integer.parseInt(queryParam.get("numberOfFiles"))];
[...] // I process the data in this entire method and send it to the previous method that creates a zip
// Get a reference to the zipped file
File selectedFilesZipFile = Controller.getDownloadZip(files, folderName);
// Set the appropiate Content-Type
exchange.getResponseHeaders().set("Content-Type", "application/zip");
// Optionally, if the file is downloaded in an anchor, set the appropiate content disposition
// exchange.getResponseHeaders().add("Content-Disposition", "attachment; filename=selected-files.zip");
// Download the file. I used java.nio.Files to copy the file contents, but please, feel free
// to use other option like java.io or the Commons-IO library, for instance
exchange.sendResponseHeaders(200, selectedFilesZipFile.length());
try (OutputStream responseBody = httpExchange.getResponseBody()) {
Files.copy(selectedFilesZipFile.toPath(), responseBody);
responseBody.flush();
}
}
});
Now the problem is how to deal with the download in Angular.
As suggested in the previous code, if the resource is public or you have a way to manage your security token, including it as a parameter in the URL, for instance, one possible solution is to not use Angular HttpClient but an anchor with an href that points to your ever backend handler method directly.
If you need to use Angular HttpClient, perhaps to include your auth tokens, then you can try the approach proposed in this great SO question.
First, in your handler, encode to Base64 the zipped file contents to simplify the task of byte handling (in a general use case, you can typically return from your server a JSON object with the file content and metadata describing that content, like content-type, etcetera):
server.createContext("/files/downloadZip", new HttpHandler() {
#Override
public void handle(HttpExchange exchange) throws IOException {
if (!handleTokenPreflight(exchange)) { return; }
System.out.println(exchange.getRequestURI());
Map<String, String> queryParam = parseQueryParam(exchange.getRequestURI().getQuery());
String authToken = exchange.getRequestHeaders().getFirst("token");
String target = queryParam.get("target") + ",";
String[] files = new String[Integer.parseInt(queryParam.get("numberOfFiles"))];
[...] // I process the data in this entire method and send it to the previous method that creates a zip
// Get a reference to the zipped file
File selectedFilesZipFile = Controller.getDownloadZip(files, folderName);
// Set the appropiate Content-Type
exchange.getResponseHeaders().set("Content-Type", "application/zip");
// Download the file
byte[] fileContent = Files.readAllBytes(selectedFilesZipFile.toPath());
byte[] base64Data = Base64.getEncoder().encode(fileContent);
exchange.sendResponseHeaders(200, base64Data.length);
try (OutputStream responseBody = httpExchange.getResponseBody()) {
// Here I am using Commons-IO IOUtils: again, please, feel free to use other alternatives for writing
// the base64 data to the response outputstream
IOUtils.write(base64Data, responseBody);
responseBody.flush();
}
}
});
After that, use the following code in you client side Angular component to perform the download:
this.downloadService.httpGetDownloadZip(['target1','target2']).pipe(
tap((b64Data) => {
const blob = this.b64toBlob(b64Data, 'application/zip');
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl);
})
).subscribe()
As indicated in the aforementioned question, b64toBlob will look like this:
private b64toBlob(b64Data: string, contentType = '', sliceSize = 512) {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
Probably you will need to slightly modify the httpGetDownloadZip method in your service to take into account the returned base 64 data - basically, change ServerAnswer to string as the returned information type:
httpGetDownloadZip(target: string[]): Observable<string> {
const params = new HttpParams().set('target', String(target)).set('numberOfFiles', String(target.length));
const headers = new HttpHeaders().set('token', this.tokenService.getStorageToken());
const options = {
headers,
params,
};
return this.http
.get<string>(this.BASE_URL + '/files/downloadZip', options)
.pipe(catchError(this.handleError<ServerAnswer>('httpGetZip')));
}
You could try using responseType as arraybuffer.
Eg:
return this.http.get(URL_API_REST + 'download?filename=' + filename, {
responseType: 'arraybuffer'
});
In My Project including both front end (angular) and back end (java).
We used the below solution ( hope it work for you ):
Angular:
https://github.com/eligrey/FileSaver.js
let observable = this.downSvc.download(opts);
this.handleData(observable, (data) => {
let content = data;
const blob = new Blob([content], { type: 'application/pdf' });
saveAs(blob, file);
});
Java:
public void download(HttpServletRequest request,HttpServletResponse response){
....
response.setHeader("Content-Disposition",
"attachment;filename=\"" + fileName + "\"");
try (
OutputStream os = response.getOutputStream();
InputStream is = new FileInputStream(file);) {
byte[] buf = new byte[1024];
int len = 0;
while ((len = is.read(buf)) > -1) {
os.write(buf, 0, len);
}
os.flush();
}
You can still use HttpServletRequest on the server...
Then get its OutputStream and write to it.
#RequestMapping(method = RequestMethod.POST , params="action=downloadDocument")
public String downloadDocument(#RequestParam(value="documentId", required=true) String documentId,
HttpServletRequest request,
HttpServletResponse response )
{
try {
String docName = null;
String documentSavePath = getDocumentSavePath();
PDocument doc = mainService.getDocumentById(iDocumentId);
if(doc==null){
throw new RuntimeException("document with id: " + documentId + " not found!");
}
docName = doc.getName();
String path = documentSavePath + ContextUtils.fileSeperator() + docName;
response.setHeader("Content-Disposition", "inline;filename=\"" + docName + "\"");
OutputStream out = response.getOutputStream();
response.setContentType("application/word");
FileInputStream stream = new FileInputStream(path);
IOUtils.copy(stream, out);
out.flush();
out.close();
} catch(FileNotFoundException fnfe){
logger.error("Error downloading document! - document not found!!!! " + fnfe.getMessage() , fnfe);
} catch (IOException e) {
logger.error("Error downloading document!!! " + e.getMessage(),e);
}
return null;
}
I have this jsp document (below). Basically, when user types in the textbox, I want to show an error if the username exists in the database/ length<5, etc.
I want these errors to be simultaneously displayed without any refresh through jQuery/AJAX. I did this but it doesn't seem to be working. Here, CheckAvailability and Success are servlets and CheckAVailability checks the existence in database.
the JSP file:
<!DOCTYPE html>
<html>
<head>
<script src="js/jquery-1.11.3.js"></script>
<script>
$(document).ready(function() {
$('#username').keyup(function() {
var name = $('#username').val();
$.get('CheckAvailability?username='+name,function(responseText){
$('#status').text(responseText);});});
</script>
</head>
<body>
<form id="login_form" ><input type="text" placeholder="username" name="username" class="style-4" required="required" action="Success"/>
<div id="status"> </div>
CheckAvailability Servlet
public class CheckAvailability extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
Connection conn=null;
Statement s=null;
ResultSet rs=null;
PreparedStatement ps;
try {
//make connection
String userid = request.getParameter("username");
String arr;
Class.forName("oracle.jdbc.OracleDriver");
if (userid.equals("")) {
arr = "Error: User name cannot be empty";
} else if(userid.length()<5){
arr="Error: Username cannot be less than 5 characters.";
}
else
{
String table="user1.app_users";
String p = "alpha";//database password
String query = "select userid from " + table + " where userid='" + userid + "'";
String url = "jdbc:oracle:thin:system/" + p + "#localhost:1521:XE";
conn = DriverManager.getConnection(url);
s = conn.createStatement();
ps = conn.prepareStatement(query);
rs = ps.executeQuery();
if (!rs.next()) {
arr="UserID <b>" + userid + "</b> is available.";
} else {
arr= "Error: UserID <b>" + userid + "</b> is already in use.";
}
}
response.setContentType("text/plain");
response.getWriter().write(arr);
}catch (SQLException se) {
out.println("Error ->" + se.getMessage());
} catch(ClassNotFoundException ce)
{
out.println("Error ->" + ce.getMessage());
}finally {
out.close();
}
}
}
But this isn't displaying anything as I type in the text box. The servlet did fire on hitting on submit. What didn't happen was that the text didn't display alongside. The code executes, no error in my IDE on that. I can't exclusively run the servlet, it gives the error: 'HTTP method GET is not supported by this URL', i.e. when I run it with parameters. I took the input inside as in, String username="user12", and that didn't run either. Can anybody point out my mistake? I'm new to jQuery/AJAX.
This worked for me:
$(document).ready(function() {
$('#userid').keyup(function(event) {
var user=$('#userid').val();
$.get('CheckValidity',{username:user},function(responseText) {
$('#status').text(responseText);
});
});
});
Had to use a different JQuery.
Overrride doGet, because javax.servlet.http.HttpServlet doesn't have any processRequest method.
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.print("hi " + req.getParameter("username"));
}
Read this
Anyway.. how are you declaring your servlet? Through annotations? In web.xml? And what's the URL pattern?
if using web.xml:
<servlet>
<servlet-name>CheckAvailability Servlet</servlet-name>
<servlet-class>your.package.CheckAvailability</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CheckAvailability Servlet</servlet-name>
<url-pattern>/CheckAvailability</url-pattern>
</servlet-mapping>
if using annotations:
#WebServlet("/CheckAvailability")
public class Serv extends HttpServlet {
// ...
}
Hi I want to stream videos in client app but videos are located in server app. I am using java Restlet and Jquery Ajax to connect client app to server app. Through Ajax call i am connecting to Restlet. I don't know how to send response to ajax after streaming video from server side, how ajax receives response and how to play video in browser. Can any one help me to handle this.
Here is my code
Html:
<button id="playVideo" class="btn-primary">PlayVideo</button>
<video id="videoTab" height="300" width="500" style="display: none" controls ></video>
Ajax Call to server
$('#playVideo').click(function (){
var jsonObj = {};
jsonObj.userId = "siva";
jsonObj.file = "sample.mp4";
//console.log("json obje :"+ JSON.stringify(jsonObj))
// Rest call to play videos.
$.ajax({
type : 'GET',
url : config.streamVideo,
//dataType : 'json',
data : JSON.stringify(jsonObj),
contentType : "application/json",
mimeType : "video/mp4",
processData : false,
crossDomain : true,
success : function(result) {
//console.log("login result : " + JSON.stringify(result));
if (result) {
console.log("success.....");
srcPath = "data:video/mp4;"+result;
$('#videoTab').attr('src', srcPath);
$('#videoTab').css('display', 'block');
$('#videoTab').attr('autoplay', true);
} else {
alert('failed...');
}
},
error : function(){
alert('error')
}
});
});
RestletCode:
#Get
public InputRepresentation handleRequest(Representation entity) throws IOException, ResourceException {
// Set response headers
Series<Header> responseHeaders = (Series<Header>) getResponse().getAttributes().get("org.restlet.http.headers");
if (responseHeaders == null) {
responseHeaders = new Series<Header>(Header.class);
getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
}
responseHeaders.add(new Header("Access-Control-Allow-Origin", "*"));
logger.debug("+++++++++++++++++++Entered in play video restlet +++++++++++++++");
// Convert Rest type request to Servlet request
httpServletRequest = ServletUtils.getRequest(getRequest());
// Get Servlet context object.
sc = httpServletRequest.getServletContext();
// Get input file path.
logger.debug("------->getRealPath " + sc.getRealPath("/"));
String filePath = sc.getRealPath("/") + "WEB-INF\\data\\videos\\sample.mp4";
final File file = new File(filePath);
if (file.exists()) {
logger.debug("Requested file path : " + file.getAbsolutePath());
logger.debug("inputRepresentation :" + inputRepresentation);
fis = new FileInputStream(file);
inputRepresentation = new InputRepresentation(new InputStream() {
private boolean waited = false;
#Override
public int read() throws IOException {
waited = false;
// read the next byte of the FileInputStream, when reaching the
// end of the file, wait for 2 seconds and try again, in case
// the file was not completely created yet
while (true) {
byte[] b = new byte[1];
if (fis.read(b, 0, 1) > 0) {
return b[0] + 256;
} else {
if (waited) {
return -1;
} else {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
logger.error("Exception while streaming video : ", ex);
}
waited = true;
}
}
}
}
}, MediaType.VIDEO_MP4);
} else {
logger.debug("Requested file not found : " + filePath);
}
//logger.debug("inputRepresentation :");
return inputRepresentation;
}
Thanks in advance
After reading your comment, here is my understanding of what you should do.
I would not send json to a resource in order to get something, I would just send a simple GET request.
You need:
a resource that returns the file of a video according to its identifier. For the matter of illustration, let's say its url template is /videos/{videoid}
a web page that contains the links, and the empty video player
some javascript that set the "src" attribute video player with the url defined above: /videos/{videoid}. The way you compute the videoid is your own business.
Here is the server code:
the Restlet application, that defines the URI templates
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
// attaches the resource that represents a video, according to its identifier
router.attach("/videos/{videoid}", VideoServerResource.class);
// ... other instructions
return router;
}
the video server resource:
public class VideoServerResource extends ServerResource {
private File video;
#Override
protected void doInit() throws ResourceException {
String videoId = getAttribute("videoid");
// Compute path
String path = "/tmp/" + videoId + ".mp4";
video = new File(path);
// takes care of not found status responses.
setExisting(video.isFile());
}
#Get("mp4")
public File represent() {
return video;
}
}
Here is the client code. This is a sample Web page, with an empty video player. When clicking on the button, the video player is asked to play the http://example.com:9000/videos/testvideo video. In your case, the value testvideo is simply deduced from the link the user click on.
<!DOCTYPE html>
<html>
<head>
<script src="/static/jquery.js"></script>
<script>
$('#playVideo').click(function (){
srcPath = "http://127.0.0.1:9000/videos/testvideo";
$('#videoTab').attr('src', srcPath);
$('#videoTab').css('display', 'block');
$('#videoTab').attr('autoplay', true);
});
</script>
</head>
<body>
<button id="playVideo" class="btn-primary">PlayVideo</button>
<video id="videoTab" height="300" width="500" style="display: none" controls ></video>
</body>
</html>
I hope this will help you.
In GWT how do I display an image from the appengine server side blobstore given the string version of the key?
I think I have stored an image as a blob on the appengine. can someone tell me if it's correct?
try
{
FileService fileService = FileServiceFactory.getFileService();
AppEngineFile file = fileService.createNewBlobFile(content_type, fileName);
boolean lock = true;
FileWriteChannel writeChannel = fileService.openWriteChannel(file, lock);
byte[] b1 = new byte[BUFFER_SIZE];
int readBytes1;
while ((readBytes1 = is.read(b1)) != -1)
{
writeChannel.write(ByteBuffer.wrap(b1, 0, readBytes1));
}
writeChannel.closeFinally();
item_image_blob_key = fileService.getBlobKey(file).getKeyString();
}
catch (Exception e)
{
System.out.println(e.getLocalizedMessage());
e.printStackTrace(response.getWriter());
}
I sent the key back to the client and I am trying to present the image. I tried using :
ImagesService imagesService = ImagesServiceFactory
.getImagesService();
// Get the image serving URL
String imageUrl = imagesService.getServingUrl(blobKey);
but it is deprecated so I tried:
ImagesService imagesService = ImagesServiceFactory.getImagesService();
ServingUrlOptions suo = ServingUrlOptions.Builder.withBlobKey(blobKey);
String image_url = imagesService.getServingUrl(suo);
item.setProperty("image_url", image_url);
Now I get a URL which looks like this:
http://0.0.0.0:8888/_ah/img/5nXYgHwfiMmblDFldDXSew
and get create an image on the client thus:
String image_url = result.get_image_url();
System.out.println("image url is: " + image_url);
Image image = new Image();
image.setUrl(image_url);
RootPanel.get("dynamicDate").add(image);
Only a default image icon appears on the UI
so I created a servlet which accesses the blobstore thus:
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
public class ImageServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException
{
String blob_key = req.getParameter("blob-key");
if (blob_key != null)
{
BlobKey blobKey = new BlobKey(blob_key);
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
blobstoreService.serve(blobKey, res);
}
else
{
res.sendError(400, "One or more parameters are not set");
}
}
}
and a client http request:
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, "/itemmanager/image");
try
{
Request request = requestBuilder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception)
{
System.out.println(exception.getMessage());
}
public void onResponseReceived(Request request, Response response)
{
System.out.println("so far so good");
System.out.println(response.getHeadersAsString());
if (200 == response.getStatusCode())
{
}
else
{
// Handle the error. Can get the status text from response.getStatusText()
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
}
I seem to be getting text how do i get an input stream or something i can get an image with?
Finally after two days of scouring Google and stack-overflow and trying I got it!
On the server I got the upload url thus:
ImagesService imagesService = ImagesServiceFactory.getImagesService();
ServingUrlOptions suo = ServingUrlOptions.Builder.withBlobKey(blobKey);
String image_url = imagesService.getServingUrl(suo);
item.setProperty("image_url", image_url);
The appengine API produced a url which didn't work on the local mode [I think it has to do with sop cross platform issues]
http://0.0.0.0:8888/_ah/img/mR9SOTSEizec4gZYsRnuEw
but it provided a clue: namely the /_ah/img/ part of the String
So I decided to try it and gave this URL to the image "/_ah/img/mR9SOTSEizec4gZYsRnuEw"
Here is the client side code.
String imageKey = result.get_image_key();
System.out.println("category is: " + result.get_category() + " image blob key is: " + imageKey);
String image_url = result.get_image_url();
System.out.println("image url is: " + image_url);
//This doesn't work at least locally
/*Image image = new Image();
image.setUrl(image_url);
RootPanel.get("dynamicDate").add(image);*/
Image image2 = new Image();
image2.setUrl("/_ah/img/" + imageKey);
RootPanel.get("dynamicDate").add(image2);
I am learning java servlet programming and I wrote a program to upload files, I'm having a strange problem with the program. when it says it finished uploading the file and when i click the link to see it I get a 404 error and when i check the directory (where the file is supposed to be saved ) its empty. I checked the log and there are no error messages.I got the code from a book I'm using to learn servlet and jsp.
here is my java code
import java.io.*;
import java.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class FileUpload
*/
#WebServlet("/FileUpload")
public class FileUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public FileUpload() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.print("File upload success. <a href=\"/Project_One/files");
out.print("\">Click here to browse through all uploaded ");
out.println("files.</a><br>");
ServletInputStream sis = request.getInputStream();
StringWriter sw = new StringWriter();
int i = sis.read();
for(;i!=-1 && i!= '\r';i=sis.read())
{
sw.write(i);
}
sis.read(); //ditch \'n'
String delimiter = sw.toString();
while(true)
{
StringWriter h = new StringWriter();
int[] temp = new int[4];
temp[0] = (byte)sis.read();
temp[1] = (byte)sis.read();
temp[2] = (byte)sis.read();
h.write(temp[0]);
h.write(temp[1]);
h.write(temp[2]);
//read header
for(temp[3]=sis.read();temp[3]!=-1;temp[3]=sis.read())
{
if(temp[0] == '\r' &&
temp[1] == '\n' &&
temp[2] == 'r' &&
temp[3] == '\n')
{
break;
}
h.write(temp[3]);
temp[0]= temp[1];
temp[1]= temp[2];
temp[2]= temp[3];
}
String header = h.toString();
int StartName = header.indexOf("name=\"");
int endName = header.indexOf("\"",StartName+6);
if(StartName == -1|| endName == -1)
{
break;
}
String name = header.substring(StartName+6,endName);
if(name.equals("file"))
{
StartName = header.indexOf("filename=\"");
endName = header.indexOf("\"",StartName+10);
String filename = header.substring(StartName+10,endName);
ServletConfig config = getServletConfig();
ServletContext sc = config.getServletContext();
//File file = new File(sc.getRealPath("/files"));
//file.mkdirs();
FileOutputStream fos = new FileOutputStream(sc.getRealPath("/")+"/"+filename);
//write the file to disk
int length = delimiter.length();
//delimiter ="\r\n"+delimiter;
byte[] body = new byte[delimiter.length()];
for(int j=0;j<body.length-1;j++)
{
body[j]=(byte)sis.read();
fos.write(body[j]);
}
//check it wasn't a 0 length file
//if(!delimiter.equals(new String (body)))
//{
int e = body.length-1;
i=sis.read();
for(;i!=-1;i=sis.read())
{
body[e]=(byte)i;
/*fos.write(body[0]);
for(int l=0;l<body.length-1;l++)
{
body[l]=body[l+1];
}*/
//body[e]=(byte)i;
if(delimiter.equals(new String (body)))
{
break;
}
//length++;
fos.write(body[e]);
for(int k=0;k<body.length-1;k++)
{
body[k]=body[k+1];
}
length++;
}
fos.flush();
fos.close();
out.println("<p><b>Saved File:</b>"+filename+"</p>");
out.println("<p><b>Length:</b>"+ length+"</p>");
}
if(sis.read() == '-' && sis.read()=='-')
{
break;
}
}
out.println("</html>");
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
There were few changes made in the code , the changes were given in the book.
here is my HTML code
<html>
<head>
<title>Test HTML Form</title>
</head>
<body>
<p>Select a file to upload or browse currently uploaded files.</p>
<form action="http://127.0.0.1/Project_One/FileUpload"
method="post" enctype="multipart/form-data">
File:<input type="file" name:"file"><br>
<input value="Upload File" type="submit">
</form>
</body>
</html>
I'm using TomCat sever for this.
Where did you get this code from? From a decade old servlet tutorial/book? This is all unnecessarily overcomplicated. Please make sure that you're reading an up to date tutorial/book which is no older than one year.
Here's how the file upload could be done with the standard servlet 3.0 API:
#MultipartConfig
#WebServlet("/FileUpload")
public class FileUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
String filename = getFilename(filePart);
InputStream filecontent = filePart.getInputStream();
// ... (do your job here)
}
private static String getFilename(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
}
That's all. It also takes into account that the proper filename is returned. Some browsers such as MSIE namely incorrectly includes the full client side path along the filename. That might be the cause of your problem.
Further there are 2 other problems not directly related:
You should not store the uploaded file in the deploy folder. It will get lost whenever you redeploy the webapp. Store the file in a fixed path somewhere outside the deploy folder. See also for example How I save and retrieve an image on my server in a java webapp.
You should be delegating the job of generating HTML to JSP. In the end of doPost(), forward the request to a JSP:
request.getRequestDispatcher("/WEB-INF/uploadresult.jsp").forward(request, response);
See also:
Our Servlets wiki page - contains hello world examples how to use servlets properly
How to upload files to server using JSP/Servlet?
well i think this code is a bit complicated to read but there are a few points where the error could be, first of all this part :
out.println("<html>");
out.print("File upload success. <a href=\"/Project_One/files");
out.print("\">Click here to browse through all uploaded ");
out.println("files.</a><br>");
In this part your link points to Project_One/files but when you write your file :
FileOutputStream fos = new FileOutputStream(sc.getRealPath("/")+"/"+filename);
you write the file directly in the Project_One folder ( not in the files folder your html points ) , so you could try to see if the file was written in the main folder of your workspace.
Anyway i think you could understand better a code like this :
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) req;
MultipartFile multipartFile = multipartRequest.getFile("file");
byte[] content =multipartFile.getBytes();
File archivoParaGuardar= new File("/your_directory/"+multipartFile.getOriginalFilename());
try {
baos.write(content);
FileOutputStream fos = new FileOutputStream(archivoParaGuardar);
baos.writeTo(fos);
fos.close();
} catch (Exception e) {
logger.error("Error saving file ", e);
}
Hope this helps you.