вам просто нужно визуализировать байты в ответе. Мы делаем что-то вроде
def streamFile = {
// load the attachment by id passed on params
....
response.contentType = attachment.contentType.toLowerCase()
response.contentLength = attachment.data.length()
// our 'data' field is a Blob, the important thing here is to get the bytes according to
// how you get the actual downlaod
response.outputStream.write(attachment.data.getBytes(1L, attachment.data?.length() as int))
}
в нашем контроллере, и просто создайте ссылку на этот метод контроллера на gsp. В зависимости от того, как вы выбираете тип контента, браузер сделает все за вас. Если у вас есть тип изображения, например, он покажет изображение. Если у вас есть текстовый документ, браузер должен открыть соответствующую программу для системы пользователя.