อะไรคือตัวกรอง (Filter)?
ตัวกรองเป็นฟังก์ชันมาตรฐาน J2EE ที่ให้ความสามารถในการประมวลผลงานเพิ่มเติมสำหรับทุกคำขอที่ตรงกับรูปแบบ url ก่อน/หลังการส่งคำขอไปยัง Dispatcher Servlet หมายความว่าถูกจัดการโดยเว็บคอนเทนเนอร์ เช่น Tomcat ไม่ใช่สปริงคอนเทนเนอร์ ดังนั้นจึงประมวลผลคำขอ ก่อนที่จะไปถึง Dispatcher Servlet
การใช้งานตัวกรอง (Filter)
เพื่อเพิ่มตัวกรอง คุณต้องใช้อินเทอร์เฟซ Filter ของ javax.servlet ซึ่งมีเมธอด 3 เมธอด ดังต่อไปนี้
- เมธอด init
- เป็นเมธอดสำหรับการเริ่มต้นวัตถุตัวกรองและเพิ่มลงในบริการ เว็บคอนเทนเนอร์จะเรียกเมธอด init หนึ่งครั้งเพื่อเริ่มต้นวัตถุตัวกรอง จากนั้นคำขอต่อๆ ไปจะถูกประมวลผลผ่านเมธอด doFilter()
- เมธอด doFilter
- เป็นเมธอดที่ถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ทุกคำขอ HTTP ที่ตรงกับรูปแบบ url จะถูกส่งไปยัง Dispatcher Servlet และถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ Dispatcher Servlet จะส่งการตอบสนอง HTTP ไปยังไคลเอ็นต์
พารามิเตอร์ของ doFilter() มี FilterChain ซึ่ง chain.doFilter() จะส่งคำขอไปยังเป้าหมายถัดไป เราสามารถแทรกกระบวนการประมวลผลที่เราต้องการก่อน/หลัง chain.doFilter() เพื่อดำเนินการประมวลผลที่ต้องการ
- เป็นเมธอดที่ถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ทุกคำขอ HTTP ที่ตรงกับรูปแบบ url จะถูกส่งไปยัง Dispatcher Servlet และถูกเรียกใช้โดยเว็บคอนเทนเนอร์ก่อนที่ Dispatcher Servlet จะส่งการตอบสนอง HTTP ไปยังไคลเอ็นต์
- เมธอด destory
- เป็นเมธอดสำหรับการลบวัตถุตัวกรองออกจากบริการและส่งคืนทรัพยากรที่ถูกใช้ เป็นเมธอดที่ถูกเรียกใช้โดยเว็บคอนเทนเนอร์เพียงครั้งเดียว หลังจากนั้นจะไม่ได้รับการประมวลผลโดย doFilter() อีกต่อไป
ตัวอย่างรหัส - ข้อมูลจำเพาะของ Servlet
```javascript @WebFilter("/*") public class dolphagoFilter implements Filter {
FilterChain filterChain) throws IOException, ServletException { //การประมวลผลเบื้องต้นที่นี่ request.setCharacterEncoding("UTF-8"); System.out.println("doFilter() ก่อน...");
}
ตัวอย่างรหัส - @Component
```javascript @Order(1) @Component public class CustomFilter implements Filter {
}
- @Component: สามารถลงทะเบียน Filter เป็น Bean ของ Spring ได้
- @Order: สามารถระบุลำดับได้ หากมีตัวกรองหลายตัว
- หากลงทะเบียนตัวกรองที่ตรงกับข้อมูลจำเพาะของ Servlet เป็น Bean ของ Spring จะสามารถใช้ Bean อื่นๆ ที่ตรงกับข้อมูลจำเพาะของ Spring ได้
ตัวอย่างรหัส - @Configuration
```javascript @Configuration public class CustomRegistrationBean {
}
หากคุณต้องการให้ตัวกรองทำงานเฉพาะกับ URI เฉพาะ คุณสามารถลงทะเบียนตัวกรองเป็น Bean ของ Spring โดยใช้ FilterRegistrationBean
การใช้งานตัวกรอง (Filter)
มักจะรับผิดชอบในการตรวจสอบและประมวลผลพารามิเตอร์ของคำขอเอง
- งานทั่วไปที่เกี่ยวข้องกับความปลอดภัย
- เนื่องจากตัวกรองทำงานในเว็บคอนเทนเนอร์ ดังนั้นจึงสามารถตรวจสอบความปลอดภัย (XSS, การป้องกัน CSRF ฯลฯ) และบล็อกคำขอที่ไม่ถูกต้องได้ สิ่งนี้สามารถเพิ่มความปลอดภัยได้มากขึ้น เนื่องจากคำขอจะไม่ถูกส่งไปยังสปริงคอนเทนเนอร์
- การบันทึกสำหรับทุกคำขอ
- การบีบอัดรูปภาพ/ข้อมูล และการเข้ารหัสสตริง
- ตัวกรองได้ใช้ฟังก์ชันทั่วไปในแอปพลิเคชันเว็บ เช่น การบีบอัดรูปภาพหรือข้อมูล และการเข้ารหัสสตริง
- การปรับแต่ง ServletRequest
- HttpServletRequest สามารถอ่านเนื้อหาของ Body ได้เพียงครั้งเดียว ดังนั้น Filter หรือ Interceptor ไม่สามารถอ่าน Body ได้ เราสามารถสร้าง ServletRequest ที่กำหนดเองเพื่อบันทึก Body
ตัวตัดรับ (Interceptor)
อะไรคือตัวตัดรับ (Interceptor)?
ตัวตัดรับ (Interceptor) ไม่เหมือนกับตัวกรอง (Filter) ซึ่งเป็นข้อมูลจำเพาะมาตรฐาน J2EE เป็นเทคโนโลยีที่สปริงให้บริการ และสามารถอ้างอิงหรือประมวลผลคำขอและการตอบสนองก่อน/หลัง Dispatcher Servlet เรียกคอนโทรลเลอร์ หมายความว่าตัวตัดรับทำงานในสปริงคอนเท็กซ์ ต่างจากตัวกรองที่ทำงานในเว็บคอนเทนเนอร์
Dispatcher Servlet จะขอให้แมปตัวจัดการเพื่อค้นหาคอนโทรลเลอร์ที่เหมาะสม ซึ่งจะส่งคืนสายโซ่การดำเนินการ (HandlerExecutionChain) ดังนั้น หากสายโซ่การดำเนินการนี้มีตัวตัดรับที่ลงทะเบียนไว้มากกว่า 1 รายการ จะดำเนินการตัวตัดรับตามลำดับก่อนที่จะเรียกใช้คอนโทรลเลอร์ และหากไม่มีตัวตัดรับ จะเรียกใช้คอนโทรลเลอร์โดยตรง
การใช้งานตัวตัดรับ (Interceptor)
เพื่อเพิ่มตัวตัดรับ คุณต้องใช้อินเทอร์เฟซ HandlerInterceptor ของ org.springframework.web.servlet ซึ่งมีเมธอด 3 เมธอด ดังต่อไปนี้
- เมธอด preHandle
- เมธอด preHandle จะถูกเรียกใช้ก่อนที่จะเรียกใช้คอนโทรลเลอร์ ดังนั้นจึงสามารถใช้สำหรับงานประมวลผลเบื้องต้น ก่อนคอนโทรลเลอร์ หรือเพื่อประมวลผลหรือเพิ่มข้อมูลคำขอ
- พารามิเตอร์ handler ในเมธอด preHandle คือวัตถุที่เป็นนามธรรมของข้อมูลของเมธอดที่มี @RequestMapping
- ประเภทผลลัพธ์ของเมธอด preHandle คือ boolean หากผลลัพธ์เป็น true จะดำเนินการต่อในขั้นตอนถัดไป แต่หากเป็น false งานจะถูกหยุด และงานที่ตามมา (ตัวตัดรับถัดไปหรือคอนโทรลเลอร์) จะไม่ถูกดำเนินการ
- เมธอด postHandle
- เมธอด postHandle จะถูกเรียกใช้หลังจากที่คอนโทรลเลอร์ถูกเรียกใช้ ดังนั้นจึงสามารถใช้สำหรับงานประมวลผลหลังการประมวลผล หลังคอนโทรลเลอร์
- เมธอด afterCompletion
- เมธอด afterCompletion จะถูกเรียกใช้หลังจากที่งานทั้งหมดเสร็จสิ้น รวมถึงการสร้างผลลัพธ์สุดท้ายจากทุกมุมมอง
ตัวอย่างรหัส
```javascript @Component public class CustomInterceptor implements HandlerInterceptor {
}
@Configuration public class WebMvcConfiguration implements WebMvcConfigurer {
}
- ลงทะเบียนตัวตัดรับที่สร้างขึ้นเป็น Bean
- ลงทะเบียนตัวตัดรับที่สร้างขึ้นในเมธอด addInterceptors() ของอินเทอร์เฟซ WebMvcConfigurer
- ตัวตัดรับจะทำงานตามลำดับที่ลงทะเบียนไว้ใน InterceptorRegistry
การใช้งานตัวตัดรับ (Interceptor)
มักจะรับผิดชอบในการประมวลผลความถูกต้องของข้อมูลคำขอโดยใช้ตรรกะบริการ
- งานทั่วไป เช่น การรับรองความถูกต้อง/การอนุญาต
- ตัวอย่างเช่น การรับรองความถูกต้องหรือการอนุญาต ซึ่งเป็นงานที่เกี่ยวข้องกับคำขอของไคลเอ็นต์ สามารถตรวจสอบได้ก่อนที่จะส่งไปยังคอนโทรลเลอร์
- การบันทึกสำหรับการเรียกใช้ API
- สามารถบันทึกข้อมูลของไคลเอ็นต์ผ่านวัตถุ HttpServletRequest และ HttpServletResponse ที่ได้รับ
- การประมวลผลข้อมูลที่จะส่งไปยัง Controller
- สามารถประมวลผลวัตถุ HttpServletRequest และ HttpServletResponse ที่ได้รับ และส่งไปยังคอนโทรลเลอร์
- เลียนแบบ AOP
- สามารถระบุข้อมูลเพิ่มเติม เช่น ลายเซ็นของเมธอดที่จะเรียกใช้ผ่าน HandlerMethod ซึ่งเป็นพารามิเตอร์ที่ 3 ของเมธอด preHandle() เพื่อตัดสินใจว่าจะดำเนินการตรรกะหรือไม่
ตัวกรอง (Filter) vs ตัวตัดรับ (Interceptor)
- ตัวกรองจะทำงานในเว็บคอนเท็กซ์ และตัวตัดรับจะทำงานในสปริงคอนเท็กซ์ ดังนั้นจุดเวลาในการดำเนินการจึงแตกต่างกัน
- ตัวกรองสามารถจัดการก่อน/หลัง Dispatcher Servlet และตัวตัดรับสามารถจัดการก่อน/หลังคอนโทรลเลอร์ได้
- ตัวกรองเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่ไม่เกี่ยวข้องกับสปริง ตรวจสอบพารามิเตอร์อินพุตเอง หรือใช้ ServletRequest แทน HttpServletRequest
- ตัวตัดรับเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่เกี่ยวข้องกับคำขอของไคลเอ็นต์ที่เข้าสู่สปริง หรือเมื่อต้องการผสมตรรกะบริการ
- ตัวตัดรับสามารถใช้ @ControllerAdvice และ @ExceptionHandler เพื่อจัดการข้อยกเว้น แต่ตัวกรองไม่สามารถใช้เพื่อจัดการข้อยกเว้นได้
- ตัวกรองมักจะจัดการข้อยกเว้นที่เกิดขึ้นในขั้นตอนนั้นโดยตรงโดยการห่อ doFilter() รอบๆ ด้วยบล็อก try~catch
ตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver)
ตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver) คืออะไร?
ตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver) สามารถสร้างวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์ได้อย่างอ้อม
การใช้งานตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver)
สมมติว่าคำขอมาพร้อมกับโทเค็น JWT ตัวอย่างเช่น เราจำเป็นต้องตรวจสอบว่าโทเค็นนี้เป็นโทเค็นที่ถูกต้องหรือไม่ และดึง id ที่เก็บอยู่ในโทเค็นออก แล้วสร้างเป็นวัตถุผู้ใช้ที่เข้าสู่ระบบ
ในกรณีนี้ หากไม่ใช้ตัวแก้ไขอาร์กิวเมนต์ คุณจะต้องใช้วิธีการตรวจสอบโทเค็นและแปลงเป็นวัตถุผู้ใช้ที่เข้าสู่ระบบในทุกคอนโทรลเลอร์ ซึ่งจะทำให้เกิดรหัสซ้ำซ้อนในคอนโทรลเลอร์ที่จำเป็นต้องตรวจสอบผู้ใช้ และเพิ่มความรับผิดชอบของคอนโทรลเลอร์ ตัวแก้ไขอาร์กิวเมนต์ สามารถแก้ไขปัญหานี้ได้
การใช้งานตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver)
ตัวแก้ไขอาร์กิวเมนต์สามารถใช้งานได้โดยการใช้อินเทอร์เฟซ HandlerMethodArgumentResolver และอินเทอร์เฟซนี้จะระบุให้ใช้เมธอดสองเมธอดดังต่อไปนี้
```javascript boolean supportsParameter(MethodParameter parameter);
@Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
- เมธอด supportsParameter
- สร้างและแนบคำอธิบายประกอบเฉพาะกับพารามิเตอร์ของเมธอดที่ต้องการให้ตัวแก้ไขอาร์กิวเมนต์ทำงาน เมธอด supportsParameter() จะตรวจสอบว่าเมธอดที่ร้องขอมีคำอธิบายประกอบที่ต้องการหรือไม่ และส่งคืน true หากมีคำอธิบายประกอบที่ต้องการ
- เมธอด resolveArgument
- หากได้รับ true จาก supportsParameter หมายความว่ามีเมธอดที่มีคำอธิบายประกอบเฉพาะ เป็นเมธอดที่ผูกข้อมูลกับพารามิเตอร์ให้เป็นรูปแบบที่ต้องการและส่งคืน
นี่คือวิธีการใช้งานตัวแก้ไขอาร์กิวเมนต์ในคอนโทรลเลอร์
```javascript
@GetMapping("/me")
public ResponseEntity
ความแตกต่างระหว่างตัวแก้ไขอาร์กิวเมนต์ (Argument Resolver) และตัวตัดรับ (Interceptor)
- ตัวแก้ไขอาร์กิวเมนต์จะทำงานหลังจากตัวตัดรับ และจะส่งคืนวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์
- ในทางกลับกัน ตัวตัดรับจะสกัดกั้นคำขอ ก่อนที่จะเรียกใช้คอนโทรลเลอร์จริง และไม่สามารถส่งคืนวัตถุใดๆ จะมีเฉพาะประเภทผลลัพธ์ boolean หรือ void เท่านั้น
แหล่งที่มา
- https://mangkyu.tistory.com/173
- https://junhyunny.github.io/spring-boot/filter-interceptor-and-aop/
- https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/
- https://tecoble.techcourse.co.kr/post/2021-05-24-spring-interceptor/
- https://baeldung-cn.com/spring-mvc-handlerinterceptor-vs-filter
- https://www.baeldung.com/spring-boot-add-filter
คำถามที่คาดหวังในการสัมภาษณ์และคำตอบ
ตัวกรองคืออะไร?
ตัวกรองเป็นฟังก์ชันที่ให้ความสามารถในการประมวลผลงานเพิ่มเติมสำหรับทุกคำขอที่ตรงกับรูปแบบ url ก่อน/หลังการส่งคำขอไปยัง Dispatcher Servlet และทำงานในระดับ Servlet Container
เวลาใดที่ควรใช้ตัวกรอง?
ตัวกรองสามารถใช้สำหรับประมวลผลงานทั่วไปที่ไม่เกี่ยวข้องกับสปริงได้ หรือใช้เมื่อต้องการตรวจสอบพารามิเตอร์คำขอ
ตัวอย่างเช่น งานทั่วไปที่เกี่ยวข้องกับความปลอดภัย การบันทึกสำหรับทุกคำขอ การบีบอัดรูปภาพ/ข้อมูล และการเข้ารหัสสตริง และการปรับแต่ง ServletRequest
ตัวตัดรับคืออะไร?
ตัวตัดรับสามารถอ้างอิงหรือประมวลผลคำขอและการตอบสนองก่อน/หลัง Dispatcher Servlet เรียกคอนโทรลเลอร์ และทำงานในระดับ Spring Container
เวลาใดที่ควรใช้ตัวตัดรับ?
ตัวตัดรับสามารถใช้สำหรับประมวลผลงานทั่วไปที่เกี่ยวข้องกับคำขอของไคลเอ็นต์ หรือเมื่อต้องการตรวจสอบและใช้ตรรกะบริการ
ตัวอย่างเช่น งานทั่วไป เช่น การรับรองความถูกต้อง/การอนุญาต การบันทึกสำหรับการเรียกใช้ API และการประมวลผลข้อมูลที่จะส่งไปยัง Controller
ความแตกต่างระหว่างตัวกรองและตัวตัดรับคืออะไร?
ตัวกรองจะทำงานในระดับ Servlet Container และตัวตัดรับจะทำงานในระดับ Spring Container
ตัวกรองสามารถจัดการก่อน/หลัง Dispatcher Servlet และตัวตัดรับสามารถจัดการก่อน/หลังคอนโทรลเลอร์ได้
ดังนั้น ตัวกรองจึงเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่ไม่เกี่ยวข้องกับสปริง และตัวตัดรับจึงเหมาะสำหรับใช้ในกรณีที่ต้องประมวลผลงานทั่วไปที่เกี่ยวข้องกับคำขอของไคลเอ็นต์
ตัวแก้ไขอาร์กิวเมนต์คืออะไร?
ตัวแก้ไขอาร์กิวเมนต์สามารถสร้างวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์ได้อย่างอ้อม
เวลาใดที่ควรใช้ตัวแก้ไขอาร์กิวเมนต์?
ตัวอย่างเช่น เมื่อคำขอมาพร้อมกับโทเค็น JWT เราจำเป็นต้องตรวจสอบว่าโทเค็นนี้เป็นโทเค็นที่ถูกต้องหรือไม่ และดึง id ที่เก็บอยู่ในโทเค็นออก แล้วสร้างเป็นวัตถุ LoginMember
ความแตกต่างระหว่างตัวตัดรับและตัวแก้ไขอาร์กิวเมนต์คืออะไร?
ตัวแก้ไขอาร์กิวเมนต์จะส่งคืนวัตถุที่ต้องการจากค่าที่ส่งมาพร้อมกับคำขอไปยังคอนโทรลเลอร์ ในขณะที่ตัวตัดรับไม่สามารถส่งคืนวัตถุใดๆ และตัวแก้ไขอาร์กิวเมนต์จะทำงานหลังจากตัวตัดรับ
ความคิดเห็น0