def exportExcel(){
if(!params.max) params.max = 10
if(params?.type && params.type != "html"){
response.contentType = grailsApplication.config.grails.mime.types[params.type]
response.setHeader("Content-disposition", "attachment; filename=agents.${params.extension}")
List fields = ["orgTypeId", "name"]
Map labels = ["orgTypeId":"DP Id", "name":"Name"]
def upperCase = { domain, value ->
return value.toUpperCase()
}
Map parameters = [title: "Agent List", "column.widths":[0.15, 0.4]]
Map formatters = [name: upperCase]
exportService.export(params.type, response.outputStream, Agent.list(params), fields, labels, formatters, parameters)
}
render(view: 'index',model: [organizationTypeCount: Agent.count(), organizationType: Agent.list(params)])
}
This is my code to export excel. When I click on export button. It show Failed-Network error.
If I resume download it will be downloaded.
This is the error : java.lang.IllegalStateException: getOutputStream() has already been called for this response
Please help me resolve this issue.
You cannot write attachment data to the output stream, and then render the index view; that is trying to render your view to the same output stream that you already sent the attachment to. If you remove the line rendering the index view, your code should work as expected.
If you need to generate an attachment/download AND move to another view in your browser, you will need to send two requests to do that.
Related
As each user runs through my application I hold their data and dump it into a report as follows, which at the end is created into a pdf document and is later automatically downloaded on the users side(client-side). I now want to attach this document to an email and have it forwarded to them. This is where I have troubles with the attachment.
Code as follows:
ReportDocument rd = new ReportDocument();
rd.Load(Path.Combine(Server.MapPath("~/Reports/PP_RentalAgreement.rpt")));
rd.SetParameterValue("rent_agree_no", _1);
rd.SetParameterValue("r_initial", _2);
rd.SetParameterValue("r_f_name", _3);
rd.SetParameterValue("r_l_name", _4);
rd.SetParameterValue("r_id_no", _5);
rd.SetParameterValue("r_lic_no", _6);
rd.SetParameterValue("r_tel", _7);
rd.SetParameterValue("r_cell", _8);
rd.SetParameterValue("r_fax", _9);
Response.Buffer = false;
Response.ClearContent();
Response.ClearHeaders();
Stream st = rd.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
st.Seek(0, SeekOrigin.Begin);
if (ModelState.IsValid)
{
var m_message = new MailMessage();
m_message.To.Add(new MailAddress("JoeSoap#TextMail.com"));
m_message.Subject = "Pink Panther - Invoice";
m_message.Attachments.Add(new Attachment(st, "application/pdf", "Invoice.pdf"));
using (var smtp = new SmtpClient())
{
await smtp.SendMailAsync(m_message);
return RedirectToAction("Index");
}
}
I am getting an error on this line : m_message.Attachments.Add(new Attachment(st, "application/pdf", "Invoice.pdf")); saying The specified content type is invalid.
Someone suggested to me that I should specify a path however I am not actually saving this file anywhere
How am I able to allow the file to be attached and send it to the recipient?
The System.Net.Mail.Attachment class constructor with 3 overloads consist of these parameters:
public Attachment(System.IO.Stream contentStream, string name, string mediaType)
Hence, you're assigning name and content type in reversed order, which causing invalid content type problem at this code:
m_message.Attachments.Add(new Attachment(st, "application/pdf", "Invoice.pdf"));
The correct way is putting the file name as second argument like example below:
m_message.Attachments.Add(new Attachment(st, "Invoice.pdf", "application/pdf"));
Or using MediaTypeNames for content type setting:
m_message.Attachments.Add(new Attachment(st, "Invoice.pdf", MediaTypeNames.Application.Pdf));
Following is a code fragment obtained from Grails website.
<script>
function messageKeyPress(field,event) {
var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
var message = $('#messageBox').val();
if (theCode == 13){
<g:remoteFunction action="submitMessage" params="\'message=\'+message" update="temp"/>
$('#messageBox').val('');
return false;
} else {
return true;
}
}
function retrieveLatestMessages() {
<g:remoteFunction action="retrieveLatestMessages" update="chatMessages"/>
}
function pollMessages() {
retrieveLatestMessages();
setTimeout('pollMessages()', 5000);
}
pollMessages();
</script>
The above code worked but when i added the Controller it stopped working. I meant that the records gets saved in the DB, but i am not able to retrieve the data and display on screen.
This is what i did
<g:remoteFunction controller="message" action="retrieveLatestMessages" update="chatMessages"/>
The MessageController function is as follows:
#Secured([ 'ROLE_USER'])
def retrieveLatestMessages() {
println "test"
def messages = Message.listOrderByDate(order: 'desc', max:1000)
[messages:messages.reverse()]
println messages
}
The above controller function gets executed (I see the println statements on console), but the data isn't getting populating on the screen.
Can someone help me out here
UPDATE
[{"class":"myPro.Message","id":3,"date":"2014-07-23T17:31:58Z","message":"dfdf","name":"hi"},{"class":"myPro.Message","id":2,"date":"2014-07-23T17:31:56Z","message":"dfdfdf","name":"dd"},{"class":"myPro.Message","id":1,"date":"2014-07-23T17:31:18Z","message":"xxxx","name":"fie"}]
Your method - retrieveLatestMessages() action in your case - must return a model, but it returns the output of println instead.
To make your code work, you must place the model in the last line, or explicitly return it by using return statement:
def retrieveLatestMessages() {
println "test"
def messages = Message.listOrderByDate(order: 'desc', max:1000)
println messages
[messages:messages.reverse()]
}
Try this
import grails.converters.JSON
#Secured([ 'ROLE_USER'])
def retrieveLatestMessages() {
println "test"
def messages = Message.listOrderByDate(order: 'asc', max:1000)
render messages as JSON
}
Enjoy.
I had this sample app working on mine with no issues but here is the thing, this process requires you to poll the page consistently and it is resource intensive:
I ended up writing a domainClass that was bound to a Datasource that was using the HQL db and was outside of my own app, the process requires a DB table to stream chat....
Alternative is to move away from polling and use websockets:
check out this video
https://www.youtube.com/watch?v=8QBdUcFqRkU
Then check out this video
https://www.youtube.com/watch?v=BikL52HYaZg
Finally look at this :
https://github.com/vahidhedayati/grails-websocket-example
This has been updated and includes the 2nd method of using winsocket to make simple chat ....
I have domain property of Type Byte[].
byte[] photos
byte[] video
On GSP Page I am able to upload my files in SQL DB successfully.
When I view the page to see list of elements in a row, my action of controller does the job , how do I set the image source to this Byte array retrieved from DB.
I hope my question is clear.
After following the instructions, here is what I did..
def displayGraph() {
//def img = params.id // byte array
def classified = Classified.findById(params.id)
byte[] imageInByte=classified.photos.toByteArray();
response.setHeader('Content-length', imageInByte.length)
response.contentType = 'image/png' // or the appropriate image content type
response.outputStream << imageInByte
response.outputStream.flush()
}
In GSP Page, here is the code.
<td><img src="${createLink(controller: 'Classified', action: 'displayGraph', params: ['id': classifiedInstance.id])}"/></td>
I am getting below error now:
2014-05-03 19:17:05,723 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver -
MissingMethodException occurred when processing request:
[GET]/XXXClassified/classified/displayGraph/1
No signature of method: [B.toByteArray() is applicable for argument types: () values:
[]. Stacktrace follows: Message: No signature of method: [B.toByteArray() is applicable
for argument types: () values: []
Thanks all for your help. Finally I was able to solve this puzzle.
Here is the code that fixed by problem:
class ImageProcessingController {
def DisplayImage() {
def classified = Classified.findById(params.id)
byte[] imageInByte=classified.photos
response.contentType = 'image/png' // or the appropriate image content type
response.outputStream << imageInByte
response.outputStream.flush()
}
}
GSP code snippet:
<td><img height=100, width=100 src="${createLink(controller: 'ImageProcessing', action: 'DisplayImage', params: ['id': classifiedInstance.id])}"/></td>
=======================================================================
What I learnt:
1. response.setHeader was throwing exception. Not sure why
response.setHeader('Content-length', imageInByte.length)
2. No need to convert byte array to Byte array using "toByteArray()"
I have this problem. I have to generate a report using Jasper reports, then I have to update some records according to a some conditions. Here some code:
def crearReporte = {
//FIRST: generate the report
chain(controller:'jasper',action:'index',params:params)
//SECOND: update the reported information
def recepciones = RecepcionDeEstano.findAllByTransportePagadoAndFechaDeRecepcionBetween("NO",fechaInicial1,fechaFinal1)
pagarTransporte recepciones
}
def pagarTransporte = { lista ->
lista.each {
it.transportePagado="SI"
it.save()
}
}
My report needs the transporte_pagado record's field having the value of 'NO', but the updating operation is executed so immediately that the records and the transporte_pagado field involved are updated to 'SI' before the report is generated giving as result and empty report.
How can I delay the updating operation? Or, how can I perform a task strictly after another task is completed?
I solved my problem (Well, Sergio Michels helped me). This is the code I used (I changed some domain class and variables names to offer a general solution):
def createReport = {
Map reportParams = [:]
byte[] bytes
//report parameters
reportParams.put("PARAM_1",params.param1)
reportParams.put("PARAM_2",params.param2)
reportParams.put("PARAM_N",params.paramn)
//here I had to write some IF's to know what report to send
if(aCondition1)
def reportDef = new JasperReportDef(name:'my_report1.jasper',fileFormat:JasperExportFormat.PDF_FORMAT,parameters: reportParams)
bytes = jasperService.generateReport(reportDef).toByteArray()
//update records after they are reported
doSomeUpdate param1
}
if(aCondition2)
def reportDef = new JasperReportDef(name:'my_report2.jasper',fileFormat:JasperExportFormat.PDF_FORMAT,parameters: reportParams)
bytes = jasperService.generateReport(reportDef).toByteArray()
//update records after they are reported
doSomeUpdate param2
}
//send report for download
response.addHeader("Content-Disposition", 'attachment; filename="report.pdf"')
response.contentType = 'application/pdf'
response.outputStream << bytes
response.outputStream.flush()
}
I found that for this case is better to use the server instead of the chain. This works as a charm!
I'm trying to get a Criteria query to be exported to CSV, Excel, what have you. The issue I'm running into is that the categories code runs cleanly (as in, doesn't throw any errors), but it doesn't generate any data. I know for a fact that data is an ArrayList of List. Anyone have a workaround for this, or tell me if I'm doing something wrong?
Here's my domain object:
class Machine {
String name,
category
// constraints, etc
}
Here's my controller action (taken mostly from the plugin page):
def categories = {
if(params?.format && params.format != "html"){
response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
response.setHeader("Content-disposition", "attachment; filename=categories.${params.extension}")
def data = Machine.createCriteria().list {
projections {
groupProperty("category")
countDistinct("id")
}
}
exportService.export(params.format, response.outputStream, data, [:], [:])
}
Here's one possible solution that I thought of as soon as I submitted the question: Expando. Here's the changes to the controller method:
// response stuff above
def fields = ["category", "count"]
def labels = ["category": "Category", "count": "# of machines" ]
def data = Machine.createCriteria().list {
projections {
groupProperty("category")
countDistinct("id")
}
}.collect { l -> new Expando("category": l[0], "count": l[1]) }
exportService.export(params.format, response.outputStream, data, fields, labels, [:], [:])
I'm exploiting the fact that the Export plugin tries to get a value from an object. So, I give it an object.
If there's a better solution, I'll be more than happy to see it.