যদিও এটি একটি পুরানো প্রশ্ন, আমি এই সম্পর্কে আমার মতামত জানাতে চাই। আমি আশা করি, এটি আপনার কারও পক্ষে সহায়ক হবে।
আমি বর্তমানে একটি REST এপিআই তৈরি করছি যা স্প্রিং বুটটি 1.5.2.REREASE এর সাথে স্প্রিং ফ্রেমওয়ার্ক 4.3.7.RELEASE ব্যবহার করে A আমি জাভা কনফিগার পদ্ধতি ব্যবহার করি (এক্সএমএল কনফিগারেশনের বিপরীতে)। এছাড়াও, আমার প্রকল্পটি @RestControllerAdvice
টীকাটি ব্যবহার করে একটি বৈশ্বিক ব্যতিক্রম হ্যান্ডলিং প্রক্রিয়া ব্যবহার করে (পরে নীচে দেখুন)।
আমার প্রকল্পটি আপনার মতো একই প্রয়োজনীয়তা রয়েছে: আমি চাই যে আমার আরএসটি HTTP 404 Not Found
এপিআই ক্লায়েন্টের কাছে এইচটিটিপি প্রতিক্রিয়াতে জেএসওএন পেওলোড সহ একটি জেএসএন পেওলোডের সাথে ফিরে আসুক যখন এটি উপস্থিত নেই এমন কোনও ইউআরএলকে অনুরোধ প্রেরণের চেষ্টা করে। আমার ক্ষেত্রে, জেএসএন পে-লোডটি এর মতো দেখাচ্ছে (যা স্প্রিং বুটের ডিফল্ট, বিটিডব্লিউ থেকে স্পষ্টভাবে পৃথক রয়েছে):
{
"code": 1000,
"message": "No handler found for your request.",
"timestamp": "2017-11-20T02:40:57.628Z"
}
আমি শেষ পর্যন্ত এটি কাজ করে। সংক্ষিপ্তভাবে আপনার যা করতে হবে তা এখানে গুরুত্বপূর্ণ:
- নিশ্চিত হয়ে নিন যে
NoHandlerFoundException
এপিআই ক্লায়েন্টরা ইউআরএলএস কল করে যার জন্য কোনও হ্যান্ডলার পদ্ধতি বিদ্যমান নেই (নীচের পদক্ষেপ 1 দেখুন) the
- একটি কাস্টম ত্রুটি শ্রেণি তৈরি করুন (আমার ক্ষেত্রে
ApiError
) যা এপিআই ক্লায়েন্টকে ফিরিয়ে আনতে হবে এমন সমস্ত ডেটা রয়েছে (পদক্ষেপ 2 দেখুন)।
- একটি ব্যতিক্রম হ্যান্ডলার তৈরি করুন যা এর উপর প্রতিক্রিয়া জানায়
NoHandlerFoundException
এবং API ক্লায়েন্টকে যথাযথ ত্রুটি বার্তা দেয় (পদক্ষেপ 3 দেখুন)।
- এটির জন্য একটি পরীক্ষা লিখুন এবং নিশ্চিত হয়ে নিন, এটি কার্যকর হয় (4 ধাপ দেখুন)।
ঠিক আছে, এখন বিবরণে:
পদক্ষেপ 1: অ্যাপ্লিকেশন.প্রেটিটি কনফিগার করুন
প্রকল্পের application.properties
ফাইলে আমাকে নিম্নলিখিত দুটি কনফিগারেশন সেটিংস যুক্ত করতে হয়েছিল :
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
এটি নিশ্চিত করে যে, কোনও NoHandlerFoundException
ক্ষেত্রে কোনও ক্লায়েন্ট কোনও ইউআরএল অ্যাক্সেস করার চেষ্টা করে যার জন্য কোনও নিয়ন্ত্রণকারী পদ্ধতি উপস্থিত নেই যা অনুরোধটি পরিচালনা করতে সক্ষম হবে the
পদক্ষেপ 2: এপিআই ত্রুটিগুলির জন্য একটি শ্রেণি তৈরি করুন
ইউজেন পারাশাইভের ব্লগে এই নিবন্ধে পরামর্শ মতো একটি শ্রেণি তৈরি করেছি । এই শ্রেণিটি একটি API ত্রুটি উপস্থাপন করে। এই তথ্যটি কোনও ত্রুটির ক্ষেত্রে এইচটিটিপি প্রতিক্রিয়া সংস্থায় ক্লায়েন্টকে প্রেরণ করা হয়।
public class ApiError {
private int code;
private String message;
private Instant timestamp;
public ApiError(int code, String message) {
this.code = code;
this.message = message;
this.timestamp = Instant.now();
}
public ApiError(int code, String message, Instant timestamp) {
this.code = code;
this.message = message;
this.timestamp = timestamp;
}
// Getters and setters here...
}
পদক্ষেপ 3: একটি গ্লোবাল ব্যতিক্রম হ্যান্ডলার তৈরি / কনফিগার করুন
আমি ব্যতিক্রমগুলি হ্যান্ডেল করতে নিম্নলিখিত ক্লাসটি ব্যবহার করি (সরলতার জন্য, আমি আমদানির বিবৃতি, লগিং কোড এবং কিছু অন্যান্য, কোডের অ-প্রাসঙ্গিক টুকরো সরিয়ে ফেলেছি):
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiError noHandlerFoundException(
NoHandlerFoundException ex) {
int code = 1000;
String message = "No handler found for your request.";
return new ApiError(code, message);
}
// More exception handlers here ...
}
পদক্ষেপ 4: একটি পরীক্ষা লিখুন
আমি নিশ্চিত করতে চাই, এপিআই সর্বদা কলিং ক্লায়েন্টকে সঠিক ত্রুটি বার্তা প্রদান করে, এমনকি ব্যর্থতার ক্ষেত্রেও। সুতরাং, আমি এই মত একটি পরীক্ষা লিখেছি:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SprintBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ActiveProfiles("dev")
public class GlobalExceptionHandlerIntegrationTest {
public static final String ISO8601_DATE_REGEX =
"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$";
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(roles = "DEVICE_SCAN_HOSTS")
public void invalidUrl_returnsHttp404() throws Exception {
RequestBuilder requestBuilder = getGetRequestBuilder("/does-not-exist");
mockMvc.perform(requestBuilder)
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.code", is(1000)))
.andExpect(jsonPath("$.message", is("No handler found for your request.")))
.andExpect(jsonPath("$.timestamp", RegexMatcher.matchesRegex(ISO8601_DATE_REGEX)));
}
private RequestBuilder getGetRequestBuilder(String url) {
return MockMvcRequestBuilders
.get(url)
.accept(MediaType.APPLICATION_JSON);
}
@ActiveProfiles("dev")
টীকা দূরে রাখা যেতে পারে। আমি বিভিন্ন প্রোফাইলের সাথে কাজ করার সময়ই এটি ব্যবহার করি। RegexMatcher
একটি কাস্টম হয় Hamcrest মিলকারীর আমি ভাল হাতল টাইমস্ট্যাম্প ক্ষেত্র ব্যবহার করুন। এখানে কোডটি (আমি এটি এখানে খুঁজে পেয়েছি ):
public class RegexMatcher extends TypeSafeMatcher<String> {
private final String regex;
public RegexMatcher(final String regex) {
this.regex = regex;
}
@Override
public void describeTo(final Description description) {
description.appendText("matches regular expression=`" + regex + "`");
}
@Override
public boolean matchesSafely(final String string) {
return string.matches(regex);
}
// Matcher method you can call on this matcher class
public static RegexMatcher matchesRegex(final String string) {
return new RegexMatcher(regex);
}
}
আমার পক্ষ থেকে আরও কিছু নোট:
- স্ট্যাকওভারফ্লোতে অন্য অনেক পোস্টে লোকেরা
@EnableWebMvc
টীকাটি সেট করার পরামর্শ দেয় । আমার ক্ষেত্রে এটি প্রয়োজনীয় ছিল না।
- এই পদ্ধতির মকএমভিসি (উপরে পরীক্ষা দেখুন) এর সাথে ভাল কাজ করে।