التعامل مع الاستثناءات في Spring MVC مهم لضمان عدم إرسال استثناءات الخادم إلى العميل. اليوم سنتناول التعامل مع الاستثناءات في Spring باستخدام @ExceptionHandler، @ControllerAdvice وـ HandlerExceptionResolver. أي تطبيق ويب يتطلب تصميمًا جيدًا للتعامل مع الاستثناءات لأننا لا نريد تقديم صفحة تم إنشاؤها بواسطة الحاوية عندما يتم طرح أي استثناء غير معالج من قبل تطبيقنا.
تعامل Spring مع الاستثناءات
امتلاك نهج محدد جيدًا للتعامل مع الاستثناءات هو نقطة إيجابية كبيرة لأي إطار تطبيق ويب. وعلى هذا النحو، يقدم إطار Spring MVC طرقًا متنوعة لمساعدتنا في تحقيق تعامل فعّال مع الاستثناءات في تطبيقات الويب الخاصة بنا.
- بناء المتحكم – يمكننا تعريف طرق معالجة الاستثناءات في فئات المتحكم الخاصة بنا. كل ما نحتاجه هو تعليق هذه الطرق بتعليق
@ExceptionHandler
. يأخذ هذا التعليق فئة الاستثناء كمعامل. لذا، إذا قمنا بتعريف واحدة من هذه لفئة Exception، فسيتم معالجة جميع الاستثناءات التي يتم طرحها بواسطة طريق الطلب الخاص بنا. تعتبر هذه الطرق المعالجة للاستثناءات مشابهة لبقية طرق معالجة الطلبات، ويمكننا بناء استجابة خطأ والرد بصفحة خطأ مختلفة. يمكننا أيضًا إرسال استجابة خطأ JSON، وسننظر في ذلك لاحقًا في مثالنا. إذا كانت هناك عدة طرق معالجة استثناء محددة، فإن الطريقة المعالجة التي تكون أقرب إلى فئة الاستثناء ستستخدم. على سبيل المثال، إذا كانت لدينا طريقتين معالجتين معرفتين لIOException وException، وطريقة معالجة الطلب الخاصة بنا تثير IOException، فإن طريقة المعالجة لـ IOException ستتم تنفيذها. - معالج استثناءات عام – معالجة الاستثناءات هي مسألة متشابكة، يجب أن تتم لجميع نقاط القطع في تطبيقنا. لقد نظرنا بالفعل إلى Spring AOP ولهذا السبب يوفر Spring تعليق
@ControllerAdvice
الذي يمكننا استخدامه مع أي فئة لتعريف معالج استثناءاتنا العام. تعتبر الطرق المعالجة في مشورة المتحكم العام نفس طرق معالجة الاستثناءات المعتمدة على المتحكم وتُستخدم عندما لا تكون فئة المتحكم قادرة على معالجة الاستثناء. - HandlerExceptionResolver – بالنسبة للأخطاء العامة، في معظم الأحيان نقدم صفحات ثابتة. يوفر Spring Framework واجهة
HandlerExceptionResolver
التي يمكننا تنفيذها لإنشاء معالج استثناء عام. السبب وراء هذه الطريقة الإضافية لتحديد معالج استثناء عام هو أن Spring framework يوفر أيضًا فئات تنفيذ افتراضية يمكننا تحديدها في ملف تكوين الحاوية الخاص بنا للحصول على فوائد معالجة الاستثناءات في إطار Spring.SimpleMappingExceptionResolver
هي فئة التنفيذ الافتراضية، تسمح لنا بتكوين استثناءات الخرائط حيث يمكننا تحديد أي مورد لاستخدامه لاستثناء معين. يمكننا أيضًا تجاوزه لإنشاء معالج عام خاص بنا بتغييراتنا الخاصة بالتطبيق، مثل تسجيل رسائل الاستثناء.
لنقم بإنشاء مشروع Spring MVC حيث سننظر في تنفيذ الاستثناءات ومعالجتها بناءً على المتحكم والتجميع ومعالج الاستثناءات. سنكتب أيضًا طريقة معالجة استثناء سترجع استجابة JSON. إذا كنت جديدًا على JSON في Spring، اقرأ دليل Spring Restful JSON. سيبدو مشروعنا النهائي كما هو موضح في الصورة أدناه، سننظر في جميع مكونات التطبيق لدينا واحدة تلو الأخرى.
تعامل الاستثناءات في الربيع تعتمد على التبعيات في مافن
بالإضافة إلى التبعيات القياسية لـ Spring MVC، سنحتاج أيضًا إلى تبعية Jackson JSON لدعم JSON. يبدو ملف pom.xml النهائي لدينا كما يلي.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev.spring</groupId>
<artifactId>SpringExceptionHandling</artifactId>
<name>SpringExceptionHandling</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.6</java-version>
<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
<org.aspectj-version>1.7.4</org.aspectj-version>
<org.slf4j-version>1.7.5</org.slf4j-version>
<jackson.databind-version>2.2.3</jackson.databind-version>
</properties>
<dependencies>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.databind-version}</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
I have updated Spring Framework, AspectJ, Jackson and slf4j versions to use the latest one.
وصف نشر تعامل استثنائات Spring MVC
يبدو ملف web.xml الخاص بنا كما يلي.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/resources/404.jsp</location>
</error-page>
</web-app>
معظم الجزء مخصص لتوصيل إطار Spring بتطبيق الويب الخاص بنا، باستثناء صفحة الخطأ المحددة لخطأ 404. لذا عندما يتم إلقاء خطأ 404 في تطبيقنا، سيتم استخدام هذه الصفحة كاستجابة. يستخدم هذا التكوين من قبل الحاوية عندما يلقي تطبيق الويب الربيعي خطأ 404.
تعامل الاستثناءات في الربيع – فصول النموذج
I have defined Employee bean as model class, however we will be using it in our application just to return valid response in specific scenario. We will be deliberately throwing different types of exceptions in most of the cases.
package com.journaldev.spring.model;
public class Employee {
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
نظرًا لأننا سنقوم أيضًا بإرجاع استجابة JSON، دعونا ننشئ فول Java يحتوي على تفاصيل الاستثناء التي سيتم إرسالها كاستجابة.
package com.journaldev.spring.model;
public class ExceptionJSONInfo {
private String url;
private String message;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
معالجة الاستثناء في Spring – فئة استثناء مخصصة
لنقم بإنشاء فئة استثناء مخصصة لاستخدامها في تطبيقنا.
package com.journaldev.spring.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Employee Not Found") //404
public class EmployeeNotFoundException extends Exception {
private static final long serialVersionUID = -3332292346834265371L;
public EmployeeNotFoundException(int id){
super("EmployeeNotFoundException with id="+id);
}
}
لاحظ أنه يمكننا استخدام تعليق @ResponseStatus
مع فئات الاستثناء لتحديد رمز HTTP الذي سيتم إرساله بواسطة تطبيقنا عندما يتم طرح هذا النوع من الاستثناء من قبل تطبيقنا ويتم التعامل معه من قبل تنفيذات معالج الاستثناء لدينا. كما يمكنك رؤية أنني أقوم بتعيين حالة HTTP كـ 404 ولدينا صفحة خطأ معرفة لهذا، لذا يجب على تطبيقنا استخدام صفحة الخطأ لهذا النوع من الاستثناء إذا لم نقم بإرجاع أي عرض. يمكننا أيضًا تجاوز رمز الحالة في طريقة معالج الاستثناء الخاصة بنا، فكر فيها كرمز حالة HTTP افتراضي عندما لا تقوم طريقة معالج الاستثناء الخاصة بنا بإرجاع أي صفحة عرض كاستجابة.
معالج استثناءات تحكم Spring MVC
لنلقِ نظرة على فئة التحكم الخاصة بنا حيث سنقوم برمي أنواع مختلفة من الاستثناءات.
package com.journaldev.spring.controllers;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.journaldev.spring.exceptions.EmployeeNotFoundException;
import com.journaldev.spring.model.Employee;
import com.journaldev.spring.model.ExceptionJSONInfo;
@Controller
public class EmployeeController {
private static final Logger logger = LoggerFactory.getLogger(EmployeeController.class);
@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
public String getEmployee(@PathVariable("id") int id, Model model) throws Exception{
//رمي استثناءات مختلفة بشكل متعمد
if(id==1){
throw new EmployeeNotFoundException(id);
}else if(id==2){
throw new SQLException("SQLException, id="+id);
}else if(id==3){
throw new IOException("IOException, id="+id);
}else if(id==10){
Employee emp = new Employee();
emp.setName("Pankaj");
emp.setId(id);
model.addAttribute("employee", emp);
return "home";
}else {
throw new Exception("Generic Exception, id="+id);
}
}
@ExceptionHandler(EmployeeNotFoundException.class)
public ModelAndView handleEmployeeNotFoundException(HttpServletRequest request, Exception ex){
logger.error("Requested URL="+request.getRequestURL());
logger.error("Exception Raised="+ex);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("exception", ex);
modelAndView.addObject("url", request.getRequestURL());
modelAndView.setViewName("error");
return modelAndView;
}
}
يرجى ملاحظة أنه بالنسبة لمعالج EmployeeNotFoundException ، أنا أعيد ModelAndView وبالتالي سيتم إرسال رمز حالة HTTP كـ OK (200). إذا كان يعيد void ، فسيتم إرسال رمز حالة HTTP كـ 404. سننظر في هذا النوع من التنفيذ في تنفيذ معالج الاستثناءات العام لدينا. نظرًا لأنني أتعامل فقط مع EmployeeNotFoundException في المتحكم، سيتم التعامل مع جميع الاستثناءات الأخرى التي يتم رميها بواسطة متحكمنا من قبل معالج الاستثناءات العام.
@ControllerAdvice و @ExceptionHandler
إليك فئة تحكم معالج الاستثناءات العامة لدينا. يرجى ملاحظة أن الفئة محددة بتعليق @ControllerAdvice. كما يتم تحديد الطرق بتعليق @ExceptionHandler.
package com.journaldev.spring.controllers;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(SQLException.class)
public String handleSQLException(HttpServletRequest request, Exception ex){
logger.info("SQLException Occured:: URL="+request.getRequestURL());
return "database_error";
}
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")
@ExceptionHandler(IOException.class)
public void handleIOException(){
logger.error("IOException handler executed");
//إرجاع رمز خطأ 404
}
}
لاحظ أنه بالنسبة لـ SQLException ، أقوم بإرجاع صفحة database_error.jsp كصفحة استجابة برمز حالة HTTP يساوي 200. بالنسبة لـ IOException ، نقوم بإرجاع فارغة برمز حالة يساوي 404 ، لذلك سيتم استخدام صفحة الخطأ الخاصة بنا في هذه الحالة. كما ترون ، لم أتعامل مع أي أنواع أخرى من الاستثناءات هنا ، وهذا الجزء قد تركته لتنفيذ HandlerExceptionResolver.
HandlerExceptionResolver
نحن فقط نوسع SimpleMappingExceptionResolver ونعيد تعريف واحدة من الأساليب ، ولكن يمكننا إعادة تعريف الطريقة الأكثر أهمية لها resolveException
لتسجيل وإرسال أنواع مختلفة من صفحات العرض. ولكن هذا هو نفس استخدام تنفيذ ControllerAdvice ، لذا أتركه. سنستخدمه لتكوين صفحة العرض لجميع الاستثناءات الأخرى التي لم نتعامل معها بالرد بصفحة خطأ عامة.
ملف تكوين استثناء Spring
ملف تكوين حبة الربيع لدينا يبدو كما يلي. رمز spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="simpleMappingExceptionResolver" class="com.journaldev.spring.resolver.MySimpleMappingExceptionResolver">
<beans:property name="exceptionMappings">
<beans:map>
<beans:entry key="Exception" value="generic_error"></beans:entry>
</beans:map>
</beans:property>
<beans:property name="defaultErrorView" value="generic_error"/>
</beans:bean>
<!-- Configure to plugin JSON as request and response in method handler -->
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter"/>
</beans:list>
</beans:property>
</beans:bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</beans:bean>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
يرجى ملاحظة الفول المهيأ لدعم JSON في تطبيق الويب الخاص بنا. الجزء الوحيد المتعلق بمعالجة الاستثناءات هو تعريف فاصل simpleMappingExceptionResolver حيث نحدد generic_error.jsp كصفحة عرض لفئة Exception. هذا يضمن أن أي استثناء غير معالج من قبل تطبيقنا لن يؤدي إلى إرسال صفحة خطأ تم إنشاؤها بواسطة الخادم كاستجابة.
صفحات عرض JSP لمعالجة الاستثناءات في Spring MVC
حان الوقت للنظر في الجزء الأخير من تطبيقنا، صفحات العرض التي ستستخدم في تطبيقنا. كود home.jsp:
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<h3>Hello ${employee.name}!</h3><br>
<h4>Your ID is ${employee.id}</h4>
</body>
</html>
تستخدم home.jsp للرد ببيانات صحيحة، أي عندما نحصل على معرف 10 في طلب العميل. كود 404.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>404 Error Page</title>
</head>
<body>
<h2>Resource Not Found Error Occured, please contact support.</h2>
</body>
</html>
تستخدم 404.jsp لإنشاء عرض لكود الحالة 404 http، بالنسبة لتنفيذنا يجب أن يكون هذا الرد عندما نحصل على معرف 3 في طلب العميل. كود error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Error Page</title>
</head>
<body>
<h2>Application Error, please contact support.</h2>
<h3>Debug Information:</h3>
Requested URL= ${url}<br><br>
Exception= ${exception.message}<br><br>
<strong>Exception Stack Trace</strong><br>
<c:forEach items="${exception.stackTrace}" var="ste">
${ste}
</c:forEach>
</body>
</html>
تستخدم error.jsp عندما تقوم طريقة معالج الطلب في فئة المتحكم بإلقاء EmployeeNotFoundException. يجب أن نحصل على هذه الصفحة كرد عندما يكون قيمة المعرف 1 في طلب العميل. كود database_error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Database Error Page</title>
</head>
<body>
<h2>Database Error, please contact support.</h2>
</body>
</html>
تستخدم database_error.jsp عندما يقوم تطبيقنا بإلقاء SQLException، كما تم تهيئته في فئة GlobalExceptionHandler. يجب أن نحصل على هذه الصفحة كرد عندما تكون قيمة المعرف 2 في طلب العميل. كود generic_error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Generic Error Page</title>
</head>
<body>
<h2>Unknown Error Occured, please contact support.</h2>
</body>
</html>
هذه يجب أن تكون الصفحة كاستجابة عند حدوث أي استثناء غير متعامل معه بواسطة كود التطبيق لدينا ومرفق الرسول البسيط يتولى ذلك. يجب أن نحصل على هذه الصفحة كاستجابة عندما يكون قيمة id في طلب العميل أي شيء آخر غير 1 أو 2 أو 3 أو 10.
تشغيل تطبيق التعامل مع الاستثناءات في Spring MVC
قم بنشر التطبيق في حاوي الخدمة التي تستخدمها، أنا استخدم Apache Tomcat 7 كمثال في هذه الحالة. الصور أدناه توضح الصفحات المختلفة المرجعة من قبل تطبيقنا استنادًا إلى قيمة الهوية. المعرّف=10، استجابة صالحة. المعرّف=1، تم استخدام معالج استثناء قائم على المتحكم
المعرّف=2، تم استخدام معالج استثناء عام مع عرض كاستجابة
المعرّف=3، تم استخدام صفحة خطأ 404
المعرّف=4، تم استخدام simpleMappingExceptionResolver لعرض الاستجابة
كما يمكنك ملاحظة أننا حصلنا على الاستجابة المتوقعة في جميع الحالات.
استجابة معالج الاستثناءات JSON لفصل الربيع
نحن على وشك الانتهاء من البرنامج التعليمي الخاص بنا، باستثناء الجزء الأخير حيث سأشرح كيفية إرسال استجابة JSON من طرق معالج الاستثناءات. تحتوي تطبيقنا على جميع تبعيات JSON وتم تكوين jsonMessageConverter، كل ما نحتاجه هو تنفيذ طريقة معالج الاستثناء. لأسباب بساطة، سأعيد كتابة طريقة handleEmployeeNotFoundException() في EmployeeController لتعيد استجابة JSON. فقط قم بتحديث طريقة معالج الاستثناء في EmployeeController بالكود أدناه ونشر التطبيق مرة أخرى.
@ExceptionHandler(EmployeeNotFoundException.class)
public @ResponseBody ExceptionJSONInfo handleEmployeeNotFoundException(HttpServletRequest request, Exception ex){
ExceptionJSONInfo response = new ExceptionJSONInfo();
response.setUrl(request.getRequestURL().toString());
response.setMessage(ex.getMessage());
return response;
}
الآن عندما نستخدم id كما 1 في طلب العميل، نحصل على استجابة JSON كما هو موضح في الصورة أدناه. هذا كل شيء بالنسبة لمعالجة الاستثناءات في الربيع ومعالجة الاستثناءات في Spring MVC، يرجى تنزيل التطبيق من عنوان URL أدناه واللعب به لمعرفة المزيد.