Grails: Return 404 & show my 'Not Found' page for invalid id
What's the best way to handle invalid ids in a Grails controller action?
When MyDomainClass.get(params['i'])
returns n开发者_JAVA百科ull in my controller action I want the user to see my custom 'Not Found' page and for a 404 HTTP response code to be returned - I can't figure out the cleanest way to do this.
Thanks.
I've used the following in my controllers, where 'notFound' is a custom 404 page:
def show = {
def referenceData = ReferenceData.get( params.id )
if (referenceData)
{ return [ referenceData : referenceData ] }
else
{ redirect(uri:'/notFound') }
}
I also mapped the custom error pages in UrlMapping.groovy, something like
static mappings = {
"403"(controller: "errors", action: "forbidden")
"404"(controller: "errors", action: "notFound")
"500"(controller: "errors", action: "serverError")
}
or
static mappings = {
"403"(view: "/errors/forbidden")
"404"(view: "/errors/notFound")
"500"(view: "/errors/serverError")
}
Grails Docs - mapping to response codes
EDIT - I apologize for misreading your question. the render method takes a status code. So in the controller, if nothing is found, try
render status: 404
or
render view: you_not_found_view
or both (in one render call).
Here's my magic formula for doing this. Maybe there's a better way, but this one works and ensures the same 404 view renders whether you generate the 404 or grails does it internally (no controller found, for example).
First, create a View class that extends AbstractView:
class NotFoundView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) {
response.sendError(HttpServletResponse.SC_NOT_FOUND)
}
}
Next, create an error controller:
class ErrorController {
def notFound = {
return render(view: '/error/notFound')
}
}
Now create your error view under views/error/notFound.gsp:
<g:applyLayout name="main">
<!doctype html>
<html>
<head>
<title>Oops! Not found!</title>
</head>
<body>
<h1>Not Found</h1>
<section id="page-body">
<p>Nothing was found at your URI!</p>
</section>
</body>
</html>
</g:applyLayout>
It's crucial that you use the <g:applyLayout> tag. If you use your layout will render twice and nest itself.
Now for the URL mapping:
"404"(controller: 'error', action: 'notFound')
You're all set now to send that 404 from your controller:
def myAction = {
Thing thing = Thing.get(params.id)
if (!thing) {
return new ModelAndView(new NotFoundView())
}
}
This approach also lets you easily log the 404, try to resolve it and send a 301, or whatever you want to do.
精彩评论