我有一个Grails 2.3.7应用程序用于存储许多文件,用户可以通过URL下载他们的文件。但是,当他们进行上传并尝试通过生成的URL立即访问上传的文件时,获取" NOT FOUND"错误。如果他们等待一秒钟,他们可以正常访问该文件。
我重新加载相同的网址后很少...
我不知道它是资源的Grails框架处理器还是Tomcat 7的文件系统安全系统。我已经删除了Grails插件的资源(资源:1.2.14)来做这个测试。以下是我的BuildConfig.groovy:
grails.servlet.version = "3.0" // Change depending on target container compliance (2.5 or 3.0)
grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"
grails.project.work.dir = "target/work"
grails.project.target.level = 1.6
grails.project.source.level = 1.6
//grails.project.war.file = "target/${appName}-${appVersion}.war"
grails.project.fork = [
// configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required
// compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
// configure settings for the test-app JVM, uses the daemon by default
test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
// configure settings for the run-app JVM
run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
// configure settings for the run-war JVM
war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
// configure settings for the Console UI JVM
console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]
]
grails.project.dependency.resolver = "maven" // or ivy
grails.project.dependency.resolution = {
// inherit Grails' default dependencies
inherits("global") {
// specify dependency exclusions here; for example, uncomment this to disable ehcache:
// excludes 'ehcache'
}
log "error" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose'
checksums true // Whether to verify checksums on resolve
legacyResolve false // whether to do a secondary resolve on plugin installation, not advised and here for backwards compatibility
repositories {
inherits true // Whether to inherit repository definitions from plugins
grailsPlugins()
grailsHome()
mavenLocal()
grailsCentral()
mavenCentral()
// uncomment these (or add new ones) to enable remote dependency resolution from public Maven repositories
//mavenRepo "http://repository.codehaus.org"
//mavenRepo "http://download.java.net/maven/2/"
//mavenRepo "http://repository.jboss.com/maven2/"
mavenRepo "http://repo.spring.io/milestone/"
}
dependencies {
// specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g.
// runtime 'mysql:mysql-connector-java:5.1.27'
// runtime 'org.postgresql:postgresql:9.3-1100-jdbc41'
runtime 'postgresql:postgresql:9.1-901.jdbc4'
}
plugins {
// plugins for the build system only
build ":tomcat:7.0.53"
// plugins for the compile step
compile ":scaffolding:2.0.3"
compile ':cache:1.1.2'
// Plugin to validate CPF/CNPJ/CEP
compile ":br-validation:0.3"
compile ":spring-security-core:2.0-RC2"
compile ":spring-security-rest:1.3.4", {
excludes: 'spring-security-core'
}
// Excel, Excel 2007 & CSV Importer Using Apache POI
compile ":joda-time:1.5"
compile ":excel-import:1.0.0"
// Plugin to send emails
compile ":mandrill:0.5"
// Plugin to generate PDF
compile ":wkhtmltopdf:0.1.7"
// Plugin to scale images
compile ":hd-image-utils:1.1"
// Plugin to schedule jobs
compile ":quartz:1.0.2"
// plugins needed at runtime but not for compilation
runtime ":hibernate:3.6.10.9" // or ":hibernate4:4.3.4"
runtime ":database-migration:1.3.8"
runtime ":jquery:1.11.0.2"
// Resources com webxml
//runtime ":resources:1.2.14"
compile ":webxml:1.4.1"
// Uncomment these (or add new ones) to enable additional resources capabilities
//runtime ":zipped-resources:1.0.1"
//runtime ":cached-resources:1.1"
//runtime ":yui-minify-resources:0.1.5"
// An alternative to the default resources plugin is the asset-pipeline plugin
//compile ":asset-pipeline:1.6.1"
// Uncomment these to enable additional asset-pipeline capabilities
//compile ":sass-asset-pipeline:1.5.5"
//compile ":less-asset-pipeline:1.5.3"
//compile ":coffee-asset-pipeline:1.5.0"
//compile ":handlebars-asset-pipeline:1.3.0.1"
}
}
我的Config.grooy:
import java.text.SimpleDateFormat
// locations to search for config files that get merged into the main config;
// config files can be ConfigSlurper scripts, Java properties files, or classes
// in the classpath in ConfigSlurper format
// grails.config.locations = [ "classpath:${appName}-config.properties",
// "classpath:${appName}-config.groovy",
// "file:${userHome}/.grails/${appName}-config.properties",
// "file:${userHome}/.grails/${appName}-config.groovy"]
// if (System.properties["${appName}.config.location"]) {
// grails.config.locations << "file:" + System.properties["${appName}.config.location"]
// }
grails.project.groupId = appName // change this to alter the default package name and Maven publishing destination
// The ACCEPT header will not be used for content negotiation for user agents containing the following strings (defaults to the 4 major rendering engines)
grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident']
// URL Mapping Cache Max Size, defaults to 5000
//grails.urlmapping.cache.maxsize = 1000
// enable only when you need it
//grails.resources.resourceLocatorEnabled = true
// What URL patterns should be processed by the resources plugin
grails.resources.adhoc.includes = ['**/images/**', '**/upload/**', '**/profile/**', '**/users/**', '**/photos/**', '/css/**', '/js/**', '/plugins/**']
grails.resources.adhoc.patterns = ['/images/*', '/upload/*', '/profile/*', '/users/*', '/photos/*', '/css/*', '/js/*', '/plugins/*']
//grails.resources.processing.enabled = false
//grails.resources.adhoc.patterns = []
//grails.resources.rewrite.css = false
// uri-to-url resolution cache timeout in milliseconds
// 0 == caching disabled , -1 == no timeout
grails.resources.uriToUrlCacheTimeout = 30000
// Legacy setting for codec used to encode data with ${}
//grails.views.default.codec = "html"
// The default scope for controllers. May be prototype, session or singleton.
// If unspecified, controllers are prototype scoped.
grails.controllers.defaultScope = 'singleton'
// GSP settings
grails {
views {
gsp {
encoding = 'UTF-8'
htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping
codecs {
expression = 'html' // escapes values inside ${}
scriptlet = 'html' // escapes output from scriptlets in GSPs
taglib = 'none' // escapes output from taglibs
staticparts = 'none' // escapes output from static template parts
}
}
// escapes all not-encoded output at final stage of outputting
// filteringCodecForContentType.'text/html' = 'html'
}
}
grails.converters.encoding = "UTF-8"
// scaffolding templates configuration
grails.scaffolding.templates.domainSuffix = 'Instance'
// Set to false to use the new Grails 1.2 JSONBuilder in the render method
grails.json.legacy.builder = false
// enabled native2ascii conversion of i18n properties files
grails.enable.native2ascii = true
// packages to include in Spring bean scanning
grails.spring.bean.packages = []
// whether to disable processing of multi part requests
grails.web.disable.multipart=false
// request parameters to mask when logging exceptions
grails.exceptionresolver.params.exclude = ['password']
// configure auto-caching of queries by default (if false you can cache individual queries with 'cache: true')
grails.hibernate.cache.queries = false
// configure passing transaction's read-only attribute to Hibernate session, queries and criterias
// set "singleSession = false" OSIV mode in hibernate configuration after enabling
grails.hibernate.pass.readonly = false
// configure passing read-only to OSIV session by default, requires "singleSession = false" OSIV mode
grails.hibernate.osiv.readonly = false
grails.plugin.wkhtmltox.binary = "/usr/local/bin/wkhtmltopdf"
grailsApplication.config.hashCode = '2wg2+(APd;&[Ya9'
grails.regex.emailPattern = /[^\s][_A-Za-z0-9-]*@[A-Za-z0-9]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})/
grails.regex.cpfORcnpj = /([0-9]{2}[\.][0-9]{3}[\.][0-9]{3}[\\\/][0-9]{4}[-][0-9]{2})|([0-9]{3}[\.][0-9]{3}[\.][0-9]{3}[-][0-9]{2})/
grails.regex.cpf = /([0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2})/
grails.regex.cnpj = /([0-9]{2}[\.]?[0-9]{3}[\.]?[0-9]{3}[\\/]?[0-9]{4}[-]?[0-9]{2})/
grails.regex.is.file = /^[\w|\W]*(\.)[a-zA-Z0-9]*/
grails.regex.is.url = /^(http|https|ftp)?\:?(\/\/)?[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9\-\._\?\,\'\/\\\+&%\$#\=~])*$/
grails.regex.filesFolder = /^([image|upload]*)\/[\w]*/
grails.statics.ementa = "Ementa - "
environments {
development {
grails.logging.jul.usebridge = true
sassPath = 'sass'
courseThemeFolder = "css/"
uploadFolder = "upload/"
documentsFolder = "documents/"
meetingsFolder = "meetings/"
courseLogoUploadFolder = "images/upload/courses/logos/"
educationalProjectUploadFolder = "upload/offers/educational_projects/"
generalSettingsUploadFolder = "upload/general/settings/institution/"
programOfStudiesUploadFolder = "upload/offers/program_of_studies/"
meetingTriggersUploadFolder = "upload/meetings/triggers/"
photosUploadFolder = "upload/users/profile/photo/"
forumAttachmentFileFolder = "upload/forum/%s/%s/attachments/%s/"
documentVersionFileFolder = "upload/%s/%s/%s/documents/%s/%s/"
temporaryFilesFolder = "upload/tmp/"
grails.serverURL = "http://localhost:8080/"
grails.staticUrl = "http://localhost:8080/pemaap/"
}
production {
grails.logging.jul.usebridge = false
sassPath = '/usr/local/bin/sass'
courseThemeFolder = "css/"
uploadFolder = "upload/"
documentsFolder = "documents/"
meetingsFolder = "meetings/"
courseLogoUploadFolder = "images/upload/courses/logos/"
educationalProjectUploadFolder = "upload/offers/educational_projects/"
generalSettingsUploadFolder = "upload/general/settings/institution/"
programOfStudiesUploadFolder = "upload/offers/program_of_studies/"
meetingTriggersUploadFolder = "upload/meetings/triggers/"
photosUploadFolder = "upload/users/profile/photo/"
forumAttachmentFileFolder = "upload/forum/%s/%s/attachments/%s/"
documentVersionFileFolder = "upload/%s/%s/%s/documents/%s/%s/"
temporaryFilesFolder = "upload/tmp/"
}
}
mandrill {
apiKey = "0DltTv2M1K6YiSTchRYarg"
}
// log4j configuration
log4j = {
String fileName = new SimpleDateFormat("yyyy-MM-dd'.txt'").format(new Date());
appenders {
file name:'file', file:'/var/tmp/logs/pemaap.erros.log'
environments {
development {
rollingFile name: "file", maxFileSize: 1024,
file: ("/tmp/dev/logs/" + fileName)
}
production {
rollingFile name: "file", maxFileSize: 1024,
file: ("/tmp/prod/logs/" + fileName)
}
}
}
root {
error 'stdout', 'file'
}
}
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'br.com.tokenlab.pemaap.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'br.com.tokenlab.pemaap.UserAccessProfile'
grails.plugin.springsecurity.authority.className = 'br.com.tokenlab.pemaap.AccessProfile'
grails.plugin.springsecurity.rest.login.useJsonCredentials = true
grails.plugin.springsecurity.logout.postOnly = false
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
'/': ['permitAll'],
'/index': ['permitAll'],
'/index.gsp': ['permitAll'],
'/**/js/**': ['permitAll'],
'/**/css/**': ['permitAll'],
'/**/images/**': ['permitAll'],
'/**/favicon.ico': ['permitAll'],
'/dbconsole/**': ['permitAll'],
'/user/login': ['permitAll'],
'/user/logout': ['permitAll'],
'/**/upload/**': ['permitAll'],
'/**/users/**': ['permitAll'],
'/**/photos/**': ['permitAll'],
'/**/files/**': ['permitAll'],
'/**/tmp/**': ['permitAll'],
'/**/users/**': ['permitAll'],
'**/profile/**': ['permitAll'],
'**/photo/**': ['permitAll'],
'**/upload/users/profile/photo/**':['permitAll']
]
cors.headers = ['Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'origin, authorization, accept, content-type, x-requested-with, X-Auth-Token',
'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS']
accessProfile.type = [
["id": "1", "name": "Cliente"],
["id": "2", "name": "Prestador de Serviço"]
]
alternative.text = [
["text": "Satisfatório / Insatisfatório / Sem emissão de conceito", "alternatives": ["Satisfatório", "Insatisfatório", "Sem emissão de conceito"]],
["text": "Satisfatório / Insatisfatório", "alternatives": ["Satisfatório", "Insatisfatório"]]
]
email.sender.address = "iep@tokenlab.com.br"
//email.sender.address = "ufscar@tokenlab.com.br"
format.assessmentCategory = [
["id": "1", "name": "Formativa"],
["id": "2", "name": "Somativa"]
]
format.category = [
["id": "1", "name": "Avaliação de Atividade"],
["id": "2", "name": "Avaliação de Curso"],
["id": "3", "name": "Avaliação de Desempenho de Pessoas"]
]
format.defaultConcepts = [
[
"id": "0",
"concepts": [
"Satisfatório",
"Insatisfatório",
"Sem emissão de conceito"
]
],
[
"id": "1",
"concepts": [
"Satisfatório",
"Insatisfatório"
]
],
[
"id": "2",
"concepts": [
"Satisfatório",
"Precisa melhorar",
"Sem emissão de conceito"
]
],
[
"id": "3",
"concepts": [
"Satisfatório",
"Precisa melhorar"
]
],
[
"id": "4",
"concepts": [
"Satisfatório",
"Insatisfatório",
"Não utilizei",
"Sem emissão de conceito"
]
],
[
"id": "5",
"concepts": [
"Satisfatório",
"Insatisfatório",
"Não compareci",
"Sem emissão de conceito"
]
],
[
"id": "6",
"concepts": [
"Satisfatório",
"Insatisfatório",
"Não se aplica",
"Sem emissão de conceito"
]
]
]
individualPerson.gender = ["Masculino", "Feminino"]
meeting.movements = ["Avaliação", "Nenhum"]
offer.schemes = ["Anual", "Ciclo", "Semestral"]
offer.attendanceSchemes = ["Anual", "Semestral", "Todo o Curso"]
question.types = [
["id": "1", "name": "Dissertativa"],
["id": "2", "name": "Objetiva - Múltipla Escolha"],
["id": "3", "name": "Objetiva - Resposta Única"]
]
PS:文件存储在与网络应用程序相同的计算机上,位于同一个域中,但存储在其他端口中。上传的文件被ascyncron进程上传移动到grails web-app文件夹内的系统文件夹中。前端应用程序向grails后端应用程序发送请求并等待一些响应。在这段时间,grails尝试上传文件并将其移动到最终文件夹。
答案 0 :(得分:0)
如果您需要上传文件,那么在Amazon S3存储桶中有一个很好的选择。有一些插件可以帮助他们轻松实现,而且您永远不必担心丢失文件,而且成本非常低。