I have problem. Every time I have exception happening my spring error controller either bypasses my sitemash-freemarker decorator and just shows the error dump. Or it includes the decorator but doesn't put in the user session so the personalization in the decorator is gone.
How do you properly integrate exception handling in spring using freemarker?
Extract from web.xml:
//standard sitemash decorator and freemarker setup
<error-page>
<error-code>404</error-code>
<location>/pageNotFound.html?code=404</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/servletErrorView.html?code=500</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.html</location>
</error-page>
ErrorController.java:
@Controller
public class ErrorController extends AnnotationMethodHandlerAdapter {
private static final Logger log = Logger.getLogger(ErrorController.class);
@Autowired
private ComponentHelper helper;
@Autowired
private MailNotificationService mailNotificationService;
@RequestMapping(value = {"/servletErrorView.html", "/error.html"}, method = RequestMethod.GET)
protected ModelMap showError(HttpServletRequest req) {
String code = null, message = null, type = null, uri = null;
Object codeObj, messageObj, typeObj;
Throwable throwable;
ModelMap mm = helper.getMM();
//todo handle org.springframework.web.bind.MissingServletRequestParameterException
codeObj = req.getAttribute("javax.servlet.error.status_code");
messageObj = req.getAttribute("javax.servlet.error.message");
typeObj = req.getAttribute("javax.servlet.error.exception_type");
throwable = (Throwable) req.getAttribute("javax.servlet.error.exception");
uri = (String) req.getAttribute("javax.servlet.error.request_uri");
// Convert the attributes to string values
if (codeObj != null) code = codeObj.toString();
if (messageObj != null) message = messageObj.toString();
if (typeObj != null) type = typeObj.toString();
// The error reason is either the status code or exception type
String reason = (code != null ? code : type);
if (uri == null) {
uri = req.getRequestURI();
}
log.error("ErrorController\n reason:"+reason+"\n message:"+message+"\n uri:"+uri+"\n ",throwable);
mm.addAttribute("message", "<H4>" + reason + "</H4>" +
"<H4>" + message + "</H4>" +
"<P>" + ((throwable != null) ? getStackTrace(throwable) : "") + "</P>" +
"<I>Error accessing " + uri + "</I>");
String subject = "Error - "+reason;
String freemarkerTemplet = "/WEB-INF/freemarker/errorMail.ftl";
mailNotificationService.sendEmail(subject, "[email protected]", mm, freemarkerTemplet);
return mm;
}
public static String getStackTrace(Throwable aThrowable) {
//add the class name and any message passed to constructor
final StringBuilder result = new StringBuilder("Trace: ");
result.append(aThrowable.toString());
final String NEW_LINE = "<br>";
result.append(NEW_LINE);
//add each element of the stack trace
for (StackTraceElement element : aThrowable.getStackTrace()) {
result.append(element);
result.append(NEW_LINE);
}
return result.toString();
}
}
error.ftl
<html>
<#import "/spring.ftl" as spring/>
<#import "common.ftl" as common/>
<head>
<title>ITeezy: Error page</title>
<meta name="description" content="Error"/>
</head>
<body id="error">
<div id="main">
<h1>Error</h1>
<p><a href="<@spring.url "/index.html"/>"> <- Go back to Homepage</a></p><br>
<div id="logo"> <a href="<@spring.url "/index.html"/>"> <img src="/images/mainlogo.png" alt="[Logo]" width="260" height="140"/> </a> </div>
<#if message?exists>
<div class="message">Error: ${message}</div>
</#if>
<br>
We're sorry you received an error. Please do us a favor and let us know!
Email: <img src="/images/support-email.png" width="118" height="13"/>
with the error message and a description of what you were doing. Thanks!
<#if exception?exists>
${exception}
<#list exception.stackTrace as st>
${st}
</#list>
<#else>
<#if javax?exists && javax.servlet?exists && javax.servlet.error?exists && javax.servlet.error.exception?exists>
Servlet Exception:<p>
${javax.servlet.error.exception} <br>
${javax.servlet.error.exception.message?default("")} <br>
<#list javax.servlet.error.exception.stackTrace as st>
${st}<br>
</#list>
</#if>
</#if>
</div>
</body>
</html>
Something like this:
...and you'll get the object named
exception
in your model. Noweb.xml
configuration is required. You can specify either custom views for particular exception classes or fall back to the default view. You can as well override one of the standard resolvers to populate the model with additional data, for instance, to dump the stacktrace into a string and display it on the exception page under a spoiler block.