Trouble having java and javascript interact [duplicate] - java

I've seen this question has been asked a lot of times, but still can't manage to get my code working.
I want my webview to load some URL (say www.google.com) and then apply some javascript stored in assets/jstest.js, which contains the following:
function test(){
document.bgColor="#00FF00"; //turns to green the background color
}
And here's where I try to load the JS:
#Override
public void onPageFinished(WebView view, String url){
view.loadUrl("javascript:(function() { "
+ " document.bgColor='#FF0000';" //turns to red the background color
+ " var script=document.createElement('script'); "
+ " script.setAttribute('type','text/javascript'); "
+ " script.setAttribute('src', 'file:///android_asset/jstest.js'); "
+ " script.onload = function(){ "
+ " test(); "
+ " }; "
+ " document.getElementsByTagName('head')[0].appendChild(script); "
+ "})()");
}
I know the javascript here works because the background color actually turns to red, but for some reason it won't load jstest.js. I think the problem might be in file path (I'm certain every other line of the javascript code is correct), but it looks correct to me. And the file is in the right folder.
What am I missing?
EDIT:
Since WebResourceResponse class is available only with API Level 11, here's what I've figured out in the end.
public void onPageFinished(WebView view, String url){
String jscontent = "";
try{
InputStream is = am.open("jstest.js"); //am = Activity.getAssets()
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while (( line = br.readLine()) != null) {
jscontent += line;
}
is.close();
}
catch(Exception e){}
view.loadUrl("javascript:(" + jscontent + ")()");
}
with the jstest.js simply containing:
function() {
document.bgColor="#00FF00";
}

I tried the same thing, loading a bookmarklet (the javascript code in your loadUrl() call) into a third-party page. My bookmarklet also depends on other assets (javascript and css files) which would not load with a file:///android_asset URL.
That's because the security context of the page is still that of, e.g., http://www.google.com, and that's not allowed access to file: URLs. You should be able to see the errors if you supply/override a WebChromeClient.onConsoleMessage().
I ended up with a kludge where I changed the bookmarklet's asset references to a bogus URL scheme, like:
asset:foo/bar/baz.js
and added a WebViewClient.shouldInterceptRequest() override which looks for those and loads them from assets using AssetManager.open().
One thing I don't like about this kludge is that the asset: scheme is open to any third-party HTML/Javascript on any page my view loads, giving them access to my app's assets.
One alternative, which I didn't try, would be to embed the sub-assets in the bookmarklet using data: URLs, but that can get unwieldy.
I'd much prefer it if there was a way to manipulate the security context of just the JS bookmarklet I'm loading in loadUrl(), but I can't find anything like that.
Here's a snippet:
import android.webkit.WebResourceResponse;
...
private final class FooViewClient extends WebViewClient
{
private final String bookmarklet;
private final String scheme;
private FooViewClient(String bookmarklet, String scheme)
{
this.bookmarklet = bookmarklet;
this.scheme = scheme;
}
#Override
public void onPageFinished(WebView view, String url)
{
view.loadUrl(bookmarklet);
}
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
{
if (url.startsWith(scheme))
try
{
return new WebResourceResponse(url.endsWith("js") ? "text/javascript" : "text/css", "utf-8",
Foo.this.getAssets().open(url.substring(scheme.length())));
}
catch (IOException e)
{
Log.e(getClass().getSimpleName(), e.getMessage(), e);
}
return null;
}
}

I think the iceam cream webview client of cordova does the very thing you want to do.
It would be nice if this was documented somewhere but, as far as I can see, it is not.
Take a look at cordova's android github:
https://github.com/apache/incubator-cordova-android/blob/master/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java

Here is how i ended up doing it. I used the Content:// protocol and set up a contentprovider to handle returning a file descriptor to the system
Here is my fileContentProvider:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
public class FileContentProvider extends ContentProvider {
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) {
Log.d("FileContentProvider","fetching: " + uri);
ParcelFileDescriptor parcel = null;
String fileNameRequested = uri.getLastPathSegment();
String[] name=fileNameRequested.split("\\.");
String prefix=name[0];
String suffix=name[1];
// String path = getContext().getFilesDir().getAbsolutePath() + "/" + uri.getPath();
//String path=file:///android_asset/"+Consts.FILE_JAVASCRIPT+"
/*check if this is a javascript file*/
if(suffix.equalsIgnoreCase("js")){
InputStream is = null;
try {
is = getContext().getAssets().open("www/"+Consts.FILE_JAVASCRIPT);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
File file = stream2file(is,prefix,suffix);
try {
parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
} catch (FileNotFoundException e) {
Log.e("FileContentProvider", "uri " + uri.toString(), e);
}
}
return parcel;
}
/*converts an inputstream to a temp file*/
public File stream2file (InputStream in,String prefix,String suffix) {
File tempFile = null;
try {
tempFile = File.createTempFile(prefix, suffix);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tempFile.deleteOnExit();
FileOutputStream out = null;
try {
out = new FileOutputStream(tempFile);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
IOUtils.copy(in, out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return tempFile;
}
#Override
public boolean onCreate() {
return true;
}
#Override
public int delete(Uri uri, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public String getType(Uri uri) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public Uri insert(Uri uri, ContentValues contentvalues) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) {
throw new UnsupportedOperationException("Not supported by this provider");
}
#Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
throw new UnsupportedOperationException("Not supported by this provider");
}
}
in the manifest i defined the provider:
<provider android:name="com.example.mypackage.FileContentProvider"
android:authorities="com.example.fileprovider"
/>
Here is the javascript o inject into the webview:
webView.loadUrl("javascript:(function() { "
+ "var script=document.createElement('script'); "
+ " script.setAttribute('type','text/javascript'); "
+ " script.setAttribute('src', 'content://com.example.fileprovider/myjavascriptfile.js'); "
/* + " script.onload = function(){ "
+ " test(); "
+ " }; "
*/ + "document.body.appendChild(script); "
+ "})();");
and here is the myjavascriptfile.js (as an example):
function changeBackground(color) {
document.body.style.backgroundColor = color;
}

Maybe you could have assets as 'html/javascript templates'. You could combine different of these text sources and string logic to compose your desired html to be loaded into the WebViewer. Then, you use .loadData instead of .loadUrl
I'm using it on my own and it seems to work pretty well.
Hope it helps!

With the following two conditions given:
minSdkVersion 21
targetSdkVersion 28
I am able to successfully load any local asset (js, png, css) via the following Java code
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
if (uri.getHost().equals("assets")) {
try {
return new WebResourceResponse(
URLConnection.guessContentTypeFromName(uri.getPath()),
"utf-8",
MainActivity.this.getAssets().open(uri.toString().substring(15)));
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
And in the HTML code I can use
<link rel="stylesheet" href="https://assets/material.min.css">
<script src="https://assets/material.min.js"></script>
<script src="https://assets/moment-with-locales.min.js"></script>
<img src="https://assets/stackoverflow.png">
In Java the following then also works (you'd also need to add a favicon.ico to the assets)
webView.loadUrl("https://assets/example.html");
Using https:// as the scheme allows me to load local assets from a page served via HTTPS without security issues due to mixed-content.
None of these require to be set:
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
webSettings.setDomStorageEnabled(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);

Related

Minecraft Spigot Plugin YML File is overwriting custom input in file

I make a plugin for my Minecraft Server and everything works well.
I use a users.yml file to store some data for every user like the groups and uuid.
Something weird is happening now, and I don't know how to solve it:
My users.yml is generating fine, no problems. All data is saved in there and I can access it.
BUT when I try to edit for example the group of the user from the default (this is the group that's assigned to every new user) to admin in the file itself and the user is joining again, the file overwrites the group to default.
What do I not see in the codes below to prevent the overwrite or did I do something wrong?
This is the function that creates the users.yml file:
public class UserList {
private static File usersFile;
private static FileConfiguration usersConf;
public static void Setup(){
usersFile = new File(Main.getInstance().getDataFolder(), "users.yml");
if(!usersFile.exists()){
try {
usersFile.createNewFile();
} catch (Exception e){
System.out.println("Error creating Usersfile: " + e);
}
}
usersConf = YamlConfiguration.loadConfiguration(usersFile);
}
public static FileConfiguration get(){
return usersConf;
}
public static void Save(){
try {
usersConf.save(usersFile);
} catch (Exception e){
System.out.println("Error saving Usersfile: " + e);
}
}
public static void reload(){
usersConf = YamlConfiguration.loadConfiguration(usersFile);
}
}
This is the code in the onEnabled() function:
#Override
public void onEnable() {
instance = this;
if (!getDataFolder().exists()) getDataFolder().mkdir();
//Erstelle users.yml mit Standardwerten
UserList.Setup();
UserList.get().addDefault("groups.admin.prefix", "§c");
UserList.get().addDefault("groups.vip.prefix", "§6");
UserList.get().addDefault("groups.default.prefix", "§7");
UserList.get().options().copyDefaults(false);
UserList.Save();
//Hole alle Usergruppen
Set<String> groups = UserList.get().getConfigurationSection("groups").getKeys(false);
//Events Registrieren
getServer().getPluginManager().registerEvents(this, this);
}
And here is the code that executes when a player is joining on the server:
#EventHandler
public void onJoin(PlayerJoinEvent e){
Player p = e.getPlayer();
if (UserList.get().get("users." + p.getName() + ".group") == null){ //<- I tried to prevent it with this if-statement but the problem must be elsewhere
UserList.get().set("users." + p.getName() + ".group", "default");
}
UserList.get().set("users." + p.getName() + ".uuid", p.getUniqueId().toString());
UserList.Save();
if (!p.hasPlayedBefore()) e.setJoinMessage(ChatColor.YELLOW + p.getName() + ChatColor.WHITE + " is new on this Server!");
else e.setJoinMessage(ChatColor.YELLOW + p.getName() + ChatColor.WHITE + " is " + ChatColor.GREEN + "Online");
}
It's thie line that create the issue:
UserList.get().options().copyDefaults(false);
You should use saveDefaultConfig() which will write the config if (and only if) the config file doesn't exist.
This method should be call with your plugin instance, and will works with your config.yml file.
If you want to copy a file when it doesn't exist, you should do like that :
File usersFile = new File(Main.getInstance().getDataFolder(), "users.yml");
if(!usersFile.exists()){
try (InputStream in = pl.getResource("users.yml");
OutputStream out = new FileOutputStream(usersFile)) {
ByteStreams.copy(in, out);
} catch (Exception e) {
e.printStackTrace();
}
}
config = YamlConfiguration.loadConfiguration(usersFile);

Java - HttpServer not serving images

I have a simple setup including a HttpServer with some context to load image and CSS files:
public class Server {
private HttpServer httpServer;
public Server(int port, String path, HttpHandler handler) {
try {
httpServer = HttpServer.create(new InetSocketAddress(port), 0);
httpServer.createContext(path, handler);
// load css files
List<String> cssFiles = new ArrayList<String>();
Files.walk(Paths.get("../css")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
cssFiles.add(filePath.getFileName().toString());
}
});
for (String cssFile : cssFiles) {
httpServer.createContext("/css/" + cssFile, new CssHandler(cssFile));
}
// load image files
List<String> imgFiles = new ArrayList<String>();
Files.walk(Paths.get("../images")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
imgFiles.add(filePath.getFileName().toString());
}
});
for (String imgFile : imgFiles) {
httpServer.createContext("/images/" + imgFile, new ImageHandler(imgFile));
}
httpServer.setExecutor(null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
this.httpServer.start();
}
}
In addition to that there is a css handler which works perfectly fine and and an image handler class, which serves images defined in html tags, BUT images which are included via css tag "background-image" cannot be loaded.. why?
ImageHandler:
class ImageHandler implements HttpHandler {
private String img;
public ImageHandler(String img) {
this.img = img;
}
#Override
public void handle(HttpExchange http) throws IOException {
if (http.getRequestMethod().equals("GET")) {
System.out.println("img transfered..." + img);
try {
StringBuilder contentBuilder = new StringBuilder();
try {
BufferedReader in = new BufferedReader(new FileReader("../images/" + img));
String str;
while ((str = in.readLine()) != null) {
contentBuilder.append(str);
}
in.close();
} catch (IOException e) {
}
String response = contentBuilder.toString();
http.sendResponseHeaders(200, response.length());
OutputStream os = http.getResponseBody();
os.write(response.getBytes());
os.flush();
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
Sooo,
this works:
<img src="images/example.png"/>
But this one doesn't work:
background-image: url("images/example.png");
Could anybody explain why and suggest how to solve this problem?
Since partial URLs are relative to the source of the style sheet, and your paths structure looks like this:
/images/example.png
/css/example.css
So image URLs in example.css should either be absolute (/images/example.png), or have the correct relative path (../images/example.png).

Access file using Java in Windows with illegal Character in path

I am using a Windows machine and Java. I'm just trying to backup a file, but I ran into an issue with an illegal character in the path ("#"). I really tried and I'm stuck. I rewrote it trying all the variations I could find or think of. Any help would be greatly appreciated.
public class SyncActionMachine {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException, URISyntaxException {
String MSI_one, MSI_two, dropBox;
GetDate getDate = new GetDate();
MSI_one = "C:\\Users\\Brian\\AppData\\Roaming\\Macromedia\\Flash Player\\#SharedObjects\\Q2965ZS7\\localhost\\ActionMachine.sol";
MSI_two = "C:\\Users\\Brian\\Desktop\\test.txt";
dropBox = "C:\\Users\\Brian\\Dropbox\\Action Machine History\\ActionMachine.sol";
File source = new File(MSI_one);
File destination = new File(dropBox);
// Attempt #1 using string with special characters
try {
Files.copy(source.toPath(), destination.toPath());
} catch (IOException iOException) {
System.out.println("Didn't work: " + iOException);
}
// Attempt #2 using URI - not really sure how to use it.
URI uri;
uri = new URI("file:///C:/Users/Brian/AppDate/Roaming/Macromedia/Flash%20Player/%23SharedObjects/Q2965ZS7/localhost/ActionMachine.sol");
Path uriSelfMadePath = Paths.get(uri);
try {
Files.copy(uriSelfMadePath, destination.toPath());
} catch (IOException iOException) {
System.out.println("Didn't work: " + iOException);
}
// Attempt #3 Suggestion from Aurasphere. Thanks again for quick response.
// Not sure what I'm suppose to do with the URL
String thePath = MSI_one;
thePath = URLEncoder.encode(thePath, "UTF-8");
Path aurasphereThePath = Paths.get(thePath);
try {
Files.copy(aurasphereThePath, destination.toPath());
} catch (IOException iOException) {
System.out.println("Didn't work: " + iOException);
}
// Attempt #4 build path using Patha and passing in augruments separately
Path pathOneByOne = Paths.get("C:", "Users", "Brian", "AppDate", "Roaming", "Macromedia", "Flash Player",
"#SharedObjects", "Q2965ZS7", "localhost", "ActionMachine.sol");
try {
Files.copy(pathOneByOne, destination.toPath());
} catch (IOException iOException) {
System.out.println("Didn't work: " + iOException);
}
// Seeing what all these path's look like
URL fileUrl = source.toURI().toURL();
URI fileUri = source.toURI();
System.out.println("------------Path Print out------------------");
System.out.println("URLEncoder : " + thePath);
Path from = Paths.get(fileUri);
System.out.println("URL : " + fileUrl);
System.out.println("URI : " + fileUri);
System.out.println("source: " + source);
}
}
Thanks for any advice.
Just use URLEncode:
String thePath = "your_path";
thePath = URLEncoder.encode(thePath, "UTF-8");
Thank you everyone that looked and commented. Must have been some sleep derived moment. Anyway here is the source, it worked fine. Turned out # was a big deal, I'm not even sure what my hang up was.
public static void main(String[] args) throws IOException, URISyntaxException {
String MSI_one, MSI_two, dropBox;
GetDate getDate = new GetDate();
MSI_one = "C:\\Users\\Brian\\AppData\\Roaming\\Macromedia\\Flash Player\\#SharedObjects\\Q2965ZS7\\localhost\\ActionMachine.sol";
MSI_two = "C:\\Users\\brian\\AppData\\Roaming\\Macromedia\\Flash Player\\#SharedObjects\\HSTARDTM\\localhost\\ActionMachine.sol";
dropBox = "C:\\Users\\brian\\Dropbox\\Action Machine History\\";
// Create new file name for backup file
dropBox = dropBox + "ActionMachine-" + getDate.today() + ".sol";
File source = new File(MSI_two);
File destination = new File(dropBox);
copyNewFile cf = new copyNewFile(source, destination);
}
public class copyNewFile {
public copyNewFile(File source, File dest) throws IOException {
CopyOption[] options = new CopyOption[]{
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES
};
Files.copy(source.toPath(), dest.toPath(), options);
System.out.println("File sucessfully copied.");
}
}

Downloading GitHub issues to .csv file

GitHub issues download using eclipse egit doesn't return anything.
Recently, i've been attempting to create a java desktop application (for windows), that will download GitHub issues from a specific GitHub issue repository, and save them in a .csv file.
I've created a simple GUI using Swing to enable the input of repository names. I'm also using eclipse's egit library to establish a connection to GitHub in order to download issues. I use authentication, entered using a .properties file in order to authenticate egit's connection with GitHub.
Here is the main code my application uses to download the issues and write them to a .csv file:
package io.github.psgs.issuesdownload;
import io.github.psgs.issuesdownload.gui.GUI;
import org.eclipse.egit.github.core.Issue;
import org.eclipse.egit.github.core.client.GitHubClient;
import org.eclipse.egit.github.core.service.IssueService;
import java.io.FileWriter;
import java.io.IOException;
public class IssuesDownload {
public static void main(String[] args) {
try {
Config.loadConfiguration();
} catch(IOException ex) {
}
GUI.main(args);
}
public static String saveIssues(String repoDetails) {
String[] repoInfo = repoDetails.split("/");
String repoOwner = repoInfo[0];
String repoName = repoInfo[1];
GitHubClient client = new GitHubClient();
client.setCredentials(Config.githubuser, Config.githubpass);
IssueService issueService = new IssueService(client);
try {
FileWriter writer = new FileWriter("issues.csv");
//String[] header = {"Id", "Title", "Creator", "Assignee", "Milestone", "State", "Body Text"};
writer.append("Id, Title, Creator, Assignee, Milestone, State, Body Text");
writer.append("\n");
for (Issue issue : issueService.getIssues(repoOwner, repoName, null)) {
//String[] data = {String.valueOf(issue.getId()), issue.getTitle(), issue.getUser().getName(), issue.getAssignee().getName(), issue.getMilestone().getTitle(), issue.getState(), issue.getBodyText()};
writer.append(String.valueOf(issue.getId()) + ",");
writer.append(issue.getTitle() + ",");
writer.append(issue.getUser().getName() + ",");
writer.append(issue.getAssignee().getName() + ",");
writer.append(issue.getMilestone().getTitle() + ",");
writer.append(issue.getState() + ",");
writer.append(issue.getBodyText());
writer.append("\n");
}
writer.flush();
writer.close();
return "Download Complete!";
} catch (IOException ex) {
System.out.println("An IOException has occured!");
ex.printStackTrace();
if (ex.getMessage().equalsIgnoreCase("api.github.com")) {
return "An error has occured, reaching " + ex.getMessage() + "! Please check your network connection.";
}
}
return "An error has occured!";
}
}
This code is also available at: https://gist.github.com/psgs/9048602
The whole repository can be found at: https://github.com/psgs/IssuesDownload
When I run this code, with the .properties file in the same directory as the compile .jar file, the GitHub issues don't appear in the .csv file. I've tested the .csv file output, and the headers write correctly when I remove the download code.
Would anybody know why this is happening? Perhaps it's an authentication problem that i've missed?
After trying a few new API wrappers, i've found an API library that works. I'm now using Kohsuke Kawaguchi's GitHub API for Java to connect to GitHub.
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>1.49</version>
</dependency>
My code now reads as follows:
package io.github.psgs.issuesdownload;
import io.github.psgs.issuesdownload.gui.GUI;
import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import java.io.FileWriter;
import java.io.IOException;
public class IssuesDownload {
public static void main(String[] args) {
try {
Config.loadConfiguration();
} catch (IOException ex) {
System.out.println("An IOException had occured while loading the configuration!");
ex.printStackTrace();
}
GUI.main(args);
}
public static String saveIssues(String repoDetails, GHIssueState issueState) {
String[] repoInfo = repoDetails.split("/");
try {
GitHub github = GitHub.connectUsingOAuth(Config.githubtoken);
GHRepository repository = github.getUser(repoInfo[0]).getRepository(repoInfo[1]);
FileWriter writer = new FileWriter("issues.csv");
writer.append("Id, Title, Creator, Assignee, Milestone, State, Body Text");
writer.append("\n");
for (GHIssue issue : repository.getIssues(issueState)) {
writer.append(String.valueOf(issue.getNumber()) + ",");
writer.append(issue.getTitle() + ",");
writer.append(issue.getUser().getLogin() + ",");
if (issue.getAssignee() != null) {
writer.append(issue.getAssignee().getName() + ",");
} else {
writer.append(" ,");
}
if (issue.getMilestone() != null) {
writer.append(issue.getMilestone().getTitle() + ",");
} else {
writer.append(" ,");
}
writer.append(issue.getState() + ",");
writer.append(issue.getBody() + ",");
writer.append("\n");
}
writer.flush();
writer.close();
return "Download Complete!";
} catch (IOException ex) {
System.out.println("An IOException has occured!");
ex.printStackTrace();
if (ex.getMessage().equalsIgnoreCase("api.github.com")) {
return "An error has occurred reaching " + ex.getMessage() + "! Please check your network connection.";
}
}
return "An error has occured!";
}
}
It looks like the method you're using is meant to be used to retrieve the issues for the currently authenticated user.
Perhaps this test (in the project's repository) would be helpful. The only difference I see is that you're not passing a singletonMap and I'm not sure you exactly have to.
public static <T> void outputCsv(String fileName, String[] headerName,
List<T> listResult, HttpServletRequest request) {
HttpServletResponse response = ResponseUtil.getResponse();
OutputStream out;
try {
// Encode file name
fileName = Util.encodeUnicodeFile(fileName, request);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/octet-stream; charset="
+ Constant.CONST_SJIS_ENCODING);
response.setHeader("Content-disposition", "attachment; filename=\""
+ fileName + "\"");
response.setCharacterEncoding(Constant.CONST_SJIS_ENCODING);
out = response.getOutputStream();
CSVWriter writer = new CSVWriter(new OutputStreamWriter(out,
Constant.CONST_WINDOW_JAPAN_ENCODING),
Constant.CONST_CSV_SEPARATOR_COMMA);
// Convert list result data to List <String[]>
List<String[]> list = convertListDataToCsvArray(listResult,
headerName);
// Write list data
writer.writeAll(list);
writer.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static <T> List<String[]> convertListDataToCsvArray(
List<T> listResult, String[] headerName) {
List<String[]> listCsv = new ArrayList<String[]>();
// First row is header
listCsv.add(headerName);
for (T object : listResult) {
// Get all fields of object
Field[] fields = object.getClass().getFields();
// Init row
String[] row = new String[headerName.length];
int index = 0;
for (Field field : fields) {
try {
if (field.getType().equals(Long.class)) {
// Read field value and set to string array
Long value = (Long) field.get(object);
row[index] = value != null ? String.valueOf(value) : "";
} else if (field.getType().equals(String.class)) {
// Read field value and set to string array
String value = (String) field.get(object);
row[index] = value != null ? value : "";
} else if (field.getType().equals(BigDecimal.class)) {
// Read field value and set to string array
BigDecimal value = (BigDecimal) field.get(object);
row[index] = value != null ? String.valueOf(value) : "";
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
index++;
}
// Add row
listCsv.add(row);
}
return listCsv;
}

Using JSoup to save the contents of this url: http://www.aw20.co.uk/images/logo.png to a file

I am try to use JSoup to get the contents of this url http://www.aw20.co.uk/images/logo.png, which is the image logo.png, and save it to a file. So far I have used JSoup to connect to http://www.aw20.co.uk and get a Document. I then went and found the absolute url for the image I am looking for, but now am not sure how to this to get the actual image. So I was hoping someone could point me in the right direction to do so? Also is there anyway I could use Jsoup.connect("http://www.aw20.co.uk/images/logo.png").get(); to get the image?
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class JGet2 {
public static void main(String[] args) {
try {
Document doc = Jsoup.connect("http://www.aw20.co.uk").get();
Elements img = doc.getElementsByTag("img");
for (Element element : img) {
String src = element.absUrl("src");
System.out.println("Image Found!");
System.out.println("src attribute is: " + src);
if (src.contains("logo.png") == true) {
System.out.println("Success");
}
getImages(src);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
private static void getImages(String src) throws IOException {
int indexName = src.lastIndexOf("/");
if (indexName == src.length()) {
src = src.substring(1, indexName);
}
indexName = src.lastIndexOf("/");
String name = src.substring(indexName, src.length());
System.out.println(name);
}
}
You can use Jsoup to fetch any URL and get the data as bytes, if you don't want to parse it as HTML. E.g.:
byte[] bytes = Jsoup.connect(imgUrl).ignoreContentType(true).execute().bodyAsBytes();
ignoreContentType(true) is set because otherwise Jsoup will throw an exception that the content is not HTML parseable -- that's OK in this case because we're using bodyAsBytes() to get the response body, rather than parsing.
Check the Jsoup Connection API for more details.
Jsoup isn't designed for downloading the content of the url.
Since you are able to use a third party library, you can try apache common IO for downloading the content of a given URL to file using:
FileUtils.copyURLToFile(URL source, File destination);
It is only one line.
This method does not work well. Please careful when using it.
byte[] bytes = Jsoup.connect(imgUrl).ignoreContentType(true).execute().bodyAsBytes();
You can use these methods or part of these methods to solve your problem.
NOTE: IMAGE_HOME is the absolute path. e.g. /home/yourname/foldername
public static String storeImageIntoFS(String imageUrl, String fileName, String relativePath) {
String imagePath = null;
try {
byte[] bytes = Jsoup.connect(imageUrl).ignoreContentType(true).execute().bodyAsBytes();
ByteBuffer buffer = ByteBuffer.wrap(bytes);
String rootTargetDirectory = IMAGE_HOME + "/"+relativePath;
imagePath = rootTargetDirectory + "/"+fileName;
saveByteBufferImage(buffer, rootTargetDirectory, fileName);
} catch (IOException e) {
e.printStackTrace();
}
return imagePath;
}
public static void saveByteBufferImage(ByteBuffer imageDataBytes, String rootTargetDirectory, String savedFileName) {
String uploadInputFile = rootTargetDirectory + "/"+savedFileName;
File rootTargetDir = new File(rootTargetDirectory);
if (!rootTargetDir.exists()) {
boolean created = rootTargetDir.mkdirs();
if (!created) {
System.out.println("Error while creating directory for location- "+rootTargetDirectory);
}
}
String[] fileNameParts = savedFileName.split("\\.");
String format = fileNameParts[fileNameParts.length-1];
File file = new File(uploadInputFile);
BufferedImage bufferedImage;
InputStream in = new ByteArrayInputStream(imageDataBytes.array());
try {
bufferedImage = ImageIO.read(in);
ImageIO.write(bufferedImage, format, file);
} catch (IOException e) {
e.printStackTrace();
}
}
Also is there anyway I could use Jsoup.connect("http://www.aw20.co.uk/images/logo.png").get(); to get the image?
No, JSoup will only get text and such but cannot be used to download files or binary data. That being said, just use the file name and path that you've gotten through JSoup and then use standard Java I/O to download the file.
I've used NIO to do the downloading. i.e.,
String imgPath = // ... url path to image
String imgFilePath = // ... file path String
URL imgUrl;
ReadableByteChannel rbc = null;
FileOutputStream fos = null;
try {
imgUrl = new URL(imgPath);
rbc = Channels.newChannel(imgUrl.openStream());
fos = new FileOutputStream(imgFilePath);
// setState(EXTRACTING + imgFilePath);
fos.getChannel().transferFrom(rbc, 0, 1 << 24);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (rbc != null) {
try {
rbc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Categories

Resources