I have an Angular web app for simple quizzes, at the end of the last quiz I bind the result into an HTML template.
Previously I could generate a pdf file using PHP mpdf library from this HTML template, now as I am building the business logic and the security in spring boot I want to do that as well in spring boot.
I used Flying saucer and i could generate a pdf file from an HTML-template in the resources folder.
The question is how can I get this HTML file from the front end and generate a pdf file out of it and download the last to my pc?
#Service
public class PdfService {
private static final String OUTPUT_FILE = "test.pdf";
private static final String UTF_8 = "UTF-8";
#Test
public void generatePdf() throws Exception {
// We set-up a Thymeleaf rendering engine. All Thymeleaf templates
// are HTML-based files located under "src/test/resources". Beside
// of the main HTML file, we also have partials like a footer.html or
// a header. We can re-use those partials in different documents.
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(HTML);
templateResolver.setCharacterEncoding(UTF_8);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
// The data in our Thymeleaf templates is not hard-coded. Instead,
// we use placeholders in our templates. We fill these placeholders
// with actual data by passing in an object. In this example, we will
// write a letter to "John Doe".
//
// Note that we could also read this data from a JSON file, a database
// a web service or whatever.
Data data = exampleDataForJohnDoe();
Context context = new Context();
context.setVariable("data", data);
// Flying Saucer needs XHTML - not just normal HTML. To make our life
// easy, we use JTidy to convert the rendered Thymeleaf template to
// XHTML. Note that this might not work for very complicated HTML. But
// it's good enough for a simple letter.
String renderedHtmlContent = templateEngine.process("template", context);
String xHtml = convertToXhtml(renderedHtmlContent);
ITextRenderer renderer = new ITextRenderer();
renderer.getFontResolver().addFont("Code39.ttf", IDENTITY_H, EMBEDDED);
// FlyingSaucer has a working directory. If you run this test, the working directory
// will be the root folder of your project. However, all files (HTML, CSS, etc.) are
// located under "/src/test/resources". So we want to use this folder as the working
// directory.
String baseUrl = FileSystems
.getDefault()
.getPath("src", "test", "resources")
.toUri()
.toURL()
.toString();
renderer.setDocumentFromString(xHtml, baseUrl);
renderer.layout();
// And finally, we create the PDF:
OutputStream outputStream = new FileOutputStream(OUTPUT_FILE);
renderer.createPDF(outputStream);
outputStream.close();
}
private Data exampleDataForJohnDoe() {
Data data = new Data();
data.setFirstname("John");
data.setLastname("Doe");
data.setStreet("Example Street 1");
data.setZipCode("12345");
data.setCity("Example City");
return data;
}
static class Data {
private String firstname;
private String lastname;
private String street;
private String zipCode;
private String city;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
private String convertToXhtml(String html) throws UnsupportedEncodingException {
Tidy tidy = new Tidy();
tidy.setInputEncoding(UTF_8);
tidy.setOutputEncoding(UTF_8);
tidy.setXHTML(true);
ByteArrayInputStream inputStream = new ByteArrayInputStream(html.getBytes(UTF_8));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
tidy.parseDOM(inputStream, outputStream);
return outputStream.toString(UTF_8);
}
Related
I´m quite new to Javascript, but know a lot about Java. Im trying to learn the basics by doing little projects, for understanding the language and code. In Java, i worked a lot with storing data from maps in json-files and, when you start the programm, the json file loads the data into the map.
An example for Java:
public Map<Integer, Client> example = new HashMap<>();
Herefor the Client class :
public class Client {
private String username;
private String password;
private String host;
public Client(String username, String password, String host) {
this.username = username;
this.password = password;
this.host = host;
}
public String getPassword() {
return password;
}
public String getHost() {
return host;
}
public String getUsername() {
return username;
}
}
I want to do the same thing, but now in Javascript. My map looks like that:
var price= new Map();
Like the Java example above, I want to load such a Map into a json file and want to load the data from the json file into my map.
Could somebody proivde me with a good example of code, how to store data from json in my map ? Even a link for a tutorial would be great!
In JS it's more common to use plain objects instead of Map().
For example, let's say you have the same Client class:
class Client {
constructor(username, password, host) {
this.username = username;
this.password = password;
this.host = host;
}
}
const client1 = new Client('username1', 'password1', 'localhost');
const client2 = new Client('username2', 'password2', 'localhost');
Your price map (int to Client) would look like this:
const price = {
1: client1,
2: client2
};
Now, you can use serialize it to json:
const json = JSON.stringify(price);
Or parse it from json:
const price = JSON.parse(json);
However, if you really want to use Map, here's a tutorial for it.
I am trying to localize the Script Files.
Currently, I am able to localize the HTML Files by using the Resources,
It is like;
BaseController;
public class BaseController : Controller
{
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
string cultureName = null;
// Attempt to read the culture cookie from Request
HttpCookie cultureCookie = Request.Cookies["_culture"];
if (cultureCookie != null)
cultureName = cultureCookie.Value;
else
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ?
Request.UserLanguages[0] : // obtain it from HTTP header AcceptLanguages
null;
// Validate culture name
cultureName = InDoor.CultureHelper.GetImplementedCulture(cultureName); // This is safe
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback, state);
}
}
Home Controller;
public class HomeController : BaseController{
...
}
Plus some classes.
To localize script, I have to merge the script file into .cshtml file, But I want both cshtml and script files be separetly.
How can I do this ?
Thanks in Advance
You may want to look at this post:
http://www.c-sharpcorner.com/uploadfile/4d9083/globalization-and-localization-in-asp-net-mvc-4/
I want to list all the files in a specific folder in my a Javascript that I use to manipulate my HTMLs.
I'm using a java method to list all the files that I to display.
Here's the the class.
public class JavaScriptInterface {
private Context context;
public JavaScriptInterface(Context current){
this.context = current;
}
#JavascriptInterface
public List<String> getFileNames(String path){
String [] files;
try {
files = context.getAssets().list(path);
ArrayList<String> testName = new ArrayList<String>();
for (String file: files) {
Log.d("File name: ", file);
file = file.replace(".js", "");
String[] fileName = file.split("_");
testName.add(fileName[1]);
}
return testName;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
Then I added this in my mainActivity
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
setToUnstrictMode();
WebView wV = (WebView)appView.getEngine().getView();
wV.addJavascriptInterface(new JavaScriptInterface(this), "jsInterface");
// Set by <content src="index.html" /> in config.xml
wV.loadUrl(launchUrl);
}
Then I tried accessing it in my JS using this function.
var getTestNames = function(){
return window.jsInterface.getFileNames("www/js/tests");
}
Apparently, It's not working.
EDIT: I noticed that I was able to call the method, the log from the method getFileNames shows up in my logs. However, for some reasons, I could not pass it properly in a variable.
Maybe just write a simple plugin. I wrote some by myself i can approve that they are working. Use tips from official cordova documentation: https://cordova.apache.org/docs/en/latest/guide/platforms/android/plugin.html
I know that it's different approach, but at least it's a working one.
I have links that call a javascript function "GetDocument" which passes the ID of the link that the user wants to retrieve to an ashx page which than retrieves the document from a database and writes it back to the users browser if it's a PDF or opens the appropriate program if it's something else. These could be PDF's, XLS, DOCX.... etc.. When the user clicks a link that is a PDF everything work just fine and the PDF is opened within the browser. When the user opens anything else though, lets say for example an xlsx excel opens a garbage file with the name of the .ashx page. No errors occur and everything works with PDF. I'm kind of at a loss.
Here is the javascript
function GetDocument(id) {
spl1.loadPage('RightContent', 'FrmDocHandler.ashx?ID=' + id);
}
Here is the .ashx page
Public Class FrmDocHandler
Implements System.Web.IHttpHandler
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim sID As String = context.Request.QueryString("id")
Dim fileName As String = String.Empty
Dim fileType As String = String.Empty
Dim bytes() As Byte
bytes = Get_Blob(fileName, fileType, sSql_GetDocument(sID))
context.Response.Clear()
'clear the content of the browser
context.Response.ClearContent()
context.Response.ClearHeaders()
context.Response.Buffer = True
'I tried both of these add header and the same result
'context.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)
context.Response.AddHeader("Content-Disposition", "inline; filename=" + fileName)
context.Response.ContentType = GetMIMEType(fileType)
context.Response.BinaryWrite(bytes)
End Sub
MIME Types returned by GetMIMEType
Public Const g_MIME_DOC As String = "application/msword"
Public Const g_MIME_DOCX As String = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
Public Const g_MIME_DOT As String = "application/msword"
Public Const g_MIME_DOTX As String = "application/vnd.openxmlformats-officedocument.wordprocessingml.template"
Public Const g_MIME_HTM As String = "text/html"
Public Const g_MIME_HTML As String = "text/html"
Public Const g_MIME_JPEG As String = "image/jpeg"
Public Const g_MIME_PDF As String = "application/pdf"
Public Const g_MIME_PPSX As String = "application/vnd.openxmlformats-officedocument.presentationml.slideshow"
Public Const g_MIME_PPT As String = "application/vnd.ms-powerpoint"
Public Const g_MIME_PPTX As String = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
Public Const g_MIME_XLS As String = "application/vnd.ms-excel"
Public Const g_MIME_XLSX As String = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Public Const g_MIME_XLTX As String = "application/vnd.openxmlformats-officedocument.spreadsheetml.template"
Public Const g_MIME_XML As String = "application/rss+xml"
The line which is probably causing the file to be opened in Excel is the following:
context.Response.ContentType = GetMIMEType(fileType)
A couple of things you can do:
Check to see what MIME type is being returned by GetMIMEType, and ensure its a PDF related one (application/pdf) rather than an Excel related one (application/vnd.ms-excel)
Check on the browser end to see what application is set to handle the mime type and/or file extension that you are sending from the server
I am developing an app for my work (social housing) and I want it to be able to allow the user to take a photo and attach it to an email so they can send it to us (pictures of repairs etc)
I'm using Phonegap and Eclipse as I want the app to be cross platform but am testing in Android primarily at the moment. Is there a way to do this? I am currently using the code below with no avail.
<script typr="text/javascript" charset="utf-8">
function camera()
{
navigator.camera.getPicture(onSuccess, onFail, { quality: 20,
destinationType: Camera.DestinationType.DATA_URL
});
function onSuccess(imageData) {
var image = document.getElementById('image');
var data = "data:image/jpeg;base64," + imageData;
var link = "mailto:johnsmith#gmail.com?body="+data+"&subject=john smith";
window.location.href = link;
}
function onFail(message) {
alert('Failed because: ' + message);
}
}
</script>
So far I've tried passing the data through to the mail app using the mailto: &attachment method but that never attaches an image (most mail apps treat this as a security hole). Then I tried to embed the base64 code of the image in the body of the email (as shown above). Unfortunately the base64 just displays as plain text and makes mail unresponsive. I've also tried using the image URI instead of the Base64 method in Phonegap but that throws an 'image.URI is not defined' error in my logcat.
Is this possible? I know I can use intents for just android as detailed in another question here but this won't work on iOS etc.
Any help would be greatly appreciated.
EDIT 02/12/2012
What I'm trying to achieve here is the same functionality you get in the native Android gallery/camera app. After you take a picture you have share options, one of which is mail. If you chose to share via mail the image is passed to the mail app as an attachment. Is there any way I can implement this same functionality in my app?
So it looks like there is no 'one size fits all' solution for this problem.
The mailto: method just doesn't pass attachments in most modern mail apps as it's seen as a security risk. So regardless of whether its an imageURI or a base64 encoded image, mailto: just won't work. The passing of 'subject' and 'body' works well though for anyone that wants to use the above code for pre-filling in an email with no attachments.
After posing this question elsewhere it looks like I'll need to use a phonegap plugin (emailComposer for iOS and WebIntent for Android) in order to pass an image sucessfully to a mail app from my phonegap app.
Thanks.
use this JAVA code to send Email with photo and text.
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Security;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
public class GMailSender extends javax.mail.Authenticator {
private String mailhost = "smtp.gmail.com";
private String user;
private String password;
private Session session;
static {
Security.addProvider(new JSSEProvider());
}
public GMailSender(String user, String password) {
this.user = user;
this.password = password;
Properties props = new Properties();
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.host", mailhost);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.quitwait", "false");
session = Session.getDefaultInstance(props, this);
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password);
}
public synchronized void sendMail(String subject, String body, String sender, String recipients) throws Exception {
try {
MimeMessage message = new MimeMessage(session);
DataHandler handler = new DataHandler(new ByteArrayDataSource(body.getBytes(), "text/plain"));
message.setSender(new InternetAddress(sender));
message.setSubject(subject);
message.setDataHandler(handler);
if (recipients.indexOf(',') > 0)
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));
else
message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));
Transport.send(message);
} catch (Exception e) {
}
}
public synchronized void sendMail(String subject, String body, String senderEmail, String recipients, String filePath,String logFilePath) throws Exception {
boolean fileExists = new File(filePath).exists();
if (fileExists) {
String from = senderEmail;
String to = recipients;
String fileAttachment = filePath;
// Define message
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject);
// create the message part
MimeBodyPart messageBodyPart = new MimeBodyPart();
// fill message
messageBodyPart.setText(body);
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
// Part two is attachment
messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(fileAttachment);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName("screenShoot.jpg");
multipart.addBodyPart(messageBodyPart);
//part three for logs
messageBodyPart = new MimeBodyPart();
DataSource sourceb = new FileDataSource(logFilePath);
messageBodyPart.setDataHandler(new DataHandler(sourceb));
messageBodyPart.setFileName("logs.txt");
multipart.addBodyPart(messageBodyPart);
// Put parts in message
message.setContent(multipart);
// Send the message
Transport.send(message);
}else{
sendMail( subject, body, senderEmail, recipients);
}
}
public class ByteArrayDataSource implements DataSource {
private byte[] data;
private String type;
public ByteArrayDataSource(byte[] data, String type) {
super();
this.data = data;
this.type = type;
}
public ByteArrayDataSource(byte[] data) {
super();
this.data = data;
}
public void setType(String type) {
this.type = type;
}
public String getContentType() {
if (type == null)
return "application/octet-stream";
else
return type;
}
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(data);
}
public String getName() {
return "ByteArrayDataSource";
}
public OutputStream getOutputStream() throws IOException {
throw new IOException("Not Supported");
}
}
}