วิธีหลีกเลี่ยงข้อยกเว้น“ เส้นทางมุมมองแบบวงกลม” ด้วยการทดสอบ Spring MVC


117

ฉันมีรหัสต่อไปนี้ในตัวควบคุมของฉัน:

@Controller
@RequestMapping("/preference")
public class PreferenceController {

    @RequestMapping(method = RequestMethod.GET, produces = "text/html")
    public String preference() {
        return "preference";
    }
}

ฉันแค่พยายามทดสอบโดยใช้การทดสอบ Spring MVCดังนี้:

@ContextConfiguration
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class PreferenceControllerTest {

    @Autowired
    private WebApplicationContext ctx;

    private MockMvc mockMvc;
    @Before
    public void setup() {
        mockMvc = webAppContextSetup(ctx).build();
    }

    @Test
    public void circularViewPathIssue() throws Exception {
        mockMvc.perform(get("/preference"))
               .andDo(print());
    }
}

ฉันได้รับข้อยกเว้นต่อไปนี้:

เส้นทางมุมมองแบบวงกลม [ค่ากำหนด]: จะส่งกลับไปยัง URL ตัวจัดการปัจจุบัน [/ ค่ากำหนด] อีกครั้ง ตรวจสอบการตั้งค่า ViewResolver ของคุณ! (คำแนะนำ: นี่อาจเป็นผลมาจากมุมมองที่ไม่ระบุเนื่องจากการสร้างชื่อมุมมองเริ่มต้น)

สิ่งที่ฉันพบว่าแปลกคือมันทำงานได้ดีเมื่อฉันโหลดการกำหนดค่าบริบท "เต็ม"ที่มีเทมเพลตและตัวแก้ไขมุมมองดังที่แสดงด้านล่าง:

<bean class="org.thymeleaf.templateresolver.ServletContextTemplateResolver" id="webTemplateResolver">
    <property name="prefix" value="WEB-INF/web-templates/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML5" />
    <property name="characterEncoding" value="UTF-8" />
    <property name="order" value="2" />
    <property name="cacheable" value="false" />
</bean>

ฉันทราบดีว่าคำนำหน้าที่เพิ่มโดยตัวแก้ไขเทมเพลตทำให้มั่นใจได้ว่าไม่มี "เส้นทางมุมมองแบบวงกลม" เมื่อแอปใช้ตัวแก้ไขเทมเพลตนี้

แต่ฉันควรจะทดสอบแอปของฉันโดยใช้การทดสอบ Spring MVC อย่างไร?


1
คุณสามารถโพสต์สิ่งที่ ViewResolverคุณใช้เมื่อมันล้มเหลวได้หรือไม่?
Sotirios Delimanolis

@SotiriosDelimanolis: ฉันไม่แน่ใจว่า Spring MVC Test ใช้ viewResolver หรือไม่ เอกสาร
balteo

8
ฉันประสบปัญหาเดียวกัน แต่ปัญหาคือฉันไม่ได้เพิ่มการพึ่งพาด้านล่าง <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-thymeleaf </artifactId> </dependency>
aamir

ใช้@RestControllerแทน@Controller
MozenRath

คำตอบ:


65

สิ่งนี้ไม่เกี่ยวข้องกับการทดสอบ Spring MVC

เมื่อคุณไม่ประกาศ a ViewResolverสปริงจะลงทะเบียนค่าเริ่มต้นInternalResourceViewResolverซึ่งสร้างอินสแตนซ์JstlViewสำหรับการแสดงผลView.

JstlViewระดับขยายInternalResourceViewซึ่งเป็น

Wrapper สำหรับ JSP หรือทรัพยากรอื่น ๆ ภายในเว็บแอปพลิเคชันเดียวกัน แสดงอ็อบเจ็กต์โมเดลเป็นแอ็ตทริบิวต์คำร้องขอและส่งต่อคำร้องขอไปยัง URL รีซอร์สที่ระบุโดยใช้ javax.servlet.RequestDispatcher

URL สำหรับมุมมองนี้ควรจะระบุทรัพยากรภายในเว็บแอปพลิเคชันซึ่งเหมาะสำหรับวิธีการส่งต่อหรือรวมของ RequestDispatcher

ตัวหนาเป็นของฉัน ใน otherwords มุมมองก่อนการแสดงผลจะพยายามที่จะได้รับในการที่จะRequestDispatcher forward()ก่อนดำเนินการนี้ให้ตรวจสอบสิ่งต่อไปนี้

if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) {
    throw new ServletException("Circular view path [" + path + "]: would dispatch back " +
                        "to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " +
                        "(Hint: This may be the result of an unspecified view, due to default view name generation.)");
}

pathชื่อมุมมองอยู่ที่ไหนสิ่งที่คุณส่งคืนจากไฟล์@Controller. preferenceในตัวอย่างนี้นั่นคือ ตัวแปรuriถือ URI /context/preferenceของการร้องขอการจัดการซึ่งเป็น

โค้ดด้านบนตระหนักดีว่าหากคุณต้องการส่งต่อไปยัง/context/preferenceservlet เดียวกัน (เนื่องจากการจัดการแบบเดียวกันก่อนหน้านี้) จะจัดการคำขอและคุณจะเข้าสู่วงวนที่ไม่มีที่สิ้นสุด


เมื่อคุณประกาศ a ThymeleafViewResolverและ a ServletContextTemplateResolverโดยเฉพาะprefixและsuffixจะสร้างสิ่งที่Viewแตกต่างกันโดยให้เส้นทางเป็นเช่น

WEB-INF/web-templates/preference.html

ThymeleafViewอินสแตนซ์ค้นหาไฟล์ที่สัมพันธ์กับServletContextพา ธ โดยใช้ไฟล์ ServletContextResourceResolver

templateInputStream = resourceResolver.getResourceAsStream(templateProcessingParameters, resourceName);`

ซึ่งในที่สุด

return servletContext.getResourceAsStream(resourceName);

สิ่งนี้ได้รับทรัพยากรที่สัมพันธ์กับServletContextเส้นทาง จากนั้นสามารถใช้TemplateEngineเพื่อสร้าง HTML ไม่มีทางเกิดขึ้นที่นี่


1
ขอบคุณสำหรับการตอบกลับโดยละเอียด ฉันเข้าใจว่าเหตุใดการวนซ้ำจึงไม่เกิดขึ้นเมื่อฉันใช้ Thymeleaf และเหตุใดจึงเกิดขึ้นเมื่อฉันไม่ใช้ตัวแก้ไขมุมมอง Thymeleaf อย่างไรก็ตามฉันยังไม่แน่ใจว่าจะเปลี่ยนการกำหนดค่าอย่างไรจึงจะสามารถทดสอบแอปของฉันได้ ...
balteo

1
@balteo เมื่อคุณใช้ได้รับการแก้ไขเป็นแฟ้มเทียบกับและคุณให้ เมื่อคุณไม่ใช้การแก้ปัญหา Spring จะใช้ค่าเริ่มต้นซึ่งค้นหาทรัพยากรด้วยไฟล์. ทรัพยากรนี้สามารถเป็นไฟล์. ในกรณีนี้เป็นเพราะพา ธแมปไปยังไฟล์. ThymleafViewResolverViewprefixsuffixInternalResourceViewResolverRequestDispatcherServlet/preferenceDispatcherServlet
Sotirios Delimanolis

2
@balteo ในการทดสอบแอปของคุณให้ระบุไฟล์ViewResolver. ไม่ThymeleafViewResolverว่าในคำถามของคุณคุณกำหนดค่าเองInternalResourceViewResolverหรือเปลี่ยนชื่อมุมมองที่คุณกำลังส่งคืนในคอนโทรลเลอร์ของคุณ
Sotirios Delimanolis

ขอบคุณขอบคุณขอบคุณ! ฉันไม่สามารถเข้าใจได้ว่าเหตุใดตัวแก้ไขมุมมองทรัพยากรภายในจึงต้องการส่งต่อแทนที่จะ "รวม" แต่ตอนนี้คำอธิบายของคุณดูเหมือนว่าการใช้ "ทรัพยากร" ในชื่อนั้นค่อนข้างคลุมเครือ คำอธิบายนี้เป็นตัวเอก
Chris Thompson

2
@ShirgillFarhanAnsari @RequestMappingวิธีการจัดการคำอธิบายประกอบที่มีStringชนิดการส่งคืน (และไม่ใช่@ResponseBody) มีค่าส่งคืนที่จัดการโดยการViewNameMethodReturnValueHandlerตีความ String เป็นชื่อมุมมองและใช้เพื่อดำเนินการตามกระบวนการที่ฉันอธิบายในคำตอบของฉัน ด้วย@ResponseBodySpring MVC จะใช้แทนRequestResponseBodyMethodProcessorซึ่งเขียน String โดยตรงไปยังการตอบสนอง HTTP เช่น ไม่มีความละเอียดในการดู
Sotirios Delimanolis

97

ฉันแก้ไขปัญหานี้โดยใช้ @ResponseBody ดังต่อไปนี้:

@RequestMapping(value = "/resturl", method = RequestMethod.GET, produces = {"application/json"})
    @ResponseStatus(HttpStatus.OK)
    @Transactional(value = "jpaTransactionManager")
    public @ResponseBody List<DomainObject> findByResourceID(@PathParam("resourceID") String resourceID) {

10
พวกเขาต้องการส่งคืน HTML โดยการแก้ไขมุมมองไม่ใช่ส่งคืนไฟล์List<DomainObject>.
Sotirios Delimanolis

2
วิธีนี้ช่วยแก้ปัญหาของฉันขณะส่งคืนการตอบกลับ JSON สำหรับ Spring rest web service ..
โจ

ดีถ้าฉันไม่ระบุ produce = {"application / json"} ก็ยังใช้ได้ มันผลิต json โดยปริยายหรือไม่?
Jay

74

@Controller@RestController

@Controllerฉันมีปัญหาเดียวกันและผมสังเกตเห็นว่าควบคุมของฉันก็ถูกกำกับด้วย แทนที่ด้วยการ@RestControllerแก้ไขปัญหา นี่คือคำอธิบายจากSpring Web MVC :

@RestController เป็นคำอธิบายประกอบที่ประกอบขึ้นเองซึ่งเป็นคำอธิบายประกอบแบบ meta ที่มี @Controller และ @ResponseBody ซึ่งระบุตัวควบคุมที่ทุกวิธีสืบทอดคำอธิบายประกอบ @ResponseBody ระดับชนิดดังนั้นจึงเขียนโดยตรงไปยังเนื้อหาการตอบสนองเทียบกับความละเอียดมุมมองและการแสดงผลด้วยเทมเพลต HTML


1
@TodorTodorov มันทำเพื่อฉัน
Igor Rodriguez

@TodorTodorov และสำหรับฉัน!
วิ่ง

3
ทำงานให้ฉันด้วย ผมมี@ControllerAdviceกับhandleXyExceptionวิธีการในนั้นซึ่งกลับวัตถุของตัวเองแทนการ ResponseEntity เพิ่ม@RestControllerที่ด้านบนของ@ControllerAdviceคำอธิบายประกอบทำงานและปัญหาจะหายไป
Igor

36

นี่คือวิธีที่ฉันแก้ไขปัญหานี้:

@Before
    public void setup() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/jsp/view/");
        viewResolver.setSuffix(".jsp");

        mockMvc = MockMvcBuilders.standaloneSetup(new HelpController())
                                 .setViewResolvers(viewResolver)
                                 .build();
    }

1
นี่เป็นกรณีทดสอบเท่านั้น ไม่ใช่สำหรับคอนโทรลเลอร์
cst1992

2
กำลังช่วยใครบางคนแก้ไขปัญหานี้ในการทดสอบหน่วยใหม่นี่คือสิ่งที่เรากำลังมองหา
Bradford2000

ฉันใช้สิ่งนี้ แต่ถึงแม้จะใส่คำนำหน้าและคำต่อท้ายผิดสำหรับตัวแก้ไขของฉันในการทดสอบ แต่ก็ใช้ได้ดี คุณสามารถให้เหตุผลเบื้องหลังสิ่งนี้ได้หรือไม่เพราะเหตุใดจึงจำเป็นต้องมี
dushyantashu

คำตอบนี้ควรได้รับการโหวตว่าถูกต้องและเฉพาะเจาะจงที่สุด
Caffeine Coder

20

ฉันใช้ Spring Boot เพื่อลองโหลดหน้าเว็บไม่ใช่ทดสอบและพบปัญหานี้ วิธีแก้ปัญหาของฉันแตกต่างจากข้างต้นเล็กน้อยเมื่อพิจารณาจากสถานการณ์ที่แตกต่างกันเล็กน้อย (แม้ว่าคำตอบเหล่านั้นจะช่วยให้ฉันเข้าใจ)

ฉันต้องเปลี่ยนการพึ่งพาการเริ่มต้น Spring Boot ใน Maven จาก:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
</dependency>

ถึง:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

แค่เปลี่ยน "เว็บ" เป็น "ไทม์ลีฟ" ก็แก้ปัญหาให้ฉันได้แล้ว


1
สำหรับฉันไม่จำเป็นต้องเปลี่ยนเว็บเริ่มต้น แต่ฉันมีการพึ่งพาไทม์ลีฟด้วยการทดสอบ <scope> </scope> เมื่อฉันลบขอบเขต "การทดสอบ" มันก็ใช้ได้ ขอบคุณสำหรับเบาะแส!
Georgina Diaz

16

นี่เป็นการแก้ไขที่ง่ายหากคุณไม่สนใจเกี่ยวกับการแสดงผลมุมมอง

สร้างคลาสย่อยของ InternalResourceViewResolver ซึ่งไม่ได้ตรวจสอบเส้นทางมุมมองแบบวงกลม:

public class StandaloneMvcTestViewResolver extends InternalResourceViewResolver {

    public StandaloneMvcTestViewResolver() {
        super();
    }

    @Override
    protected AbstractUrlBasedView buildView(final String viewName) throws Exception {
        final InternalResourceView view = (InternalResourceView) super.buildView(viewName);
        // prevent checking for circular view paths
        view.setPreventDispatchLoop(false);
        return view;
    }
}

จากนั้นตั้งค่าการทดสอบของคุณด้วย:

MockMvc mockMvc;

@Before
public void setUp() {
    final MyController controller = new MyController();

    mockMvc =
            MockMvcBuilders.standaloneSetup(controller)
                    .setViewResolvers(new StandaloneMvcTestViewResolver())
                    .build();
}

สิ่งนี้ช่วยแก้ปัญหาของฉันได้ ฉันเพิ่งเพิ่มคลาส StandaloneMvcTestViewResolver ในไดเร็กทอรีเดียวกันของการทดสอบและใช้ใน MockMvcBuilders ตามที่อธิบายไว้ข้างต้น ขอบคุณ
Matheus Araujo

ฉันมีปัญหาเดียวกันและสิ่งนี้ได้รับการแก้ไขให้ฉันเช่นกัน ขอบคุณมาก!
Johan

นี่เป็นทางออกที่ยอดเยี่ยมที่ (1) ไม่จำเป็นต้องเปลี่ยนคอนโทรลเลอร์และ (2) สามารถใช้ซ้ำได้ในคลาสทดสอบทั้งหมดด้วยการนำเข้าอย่างง่ายเพียงครั้งเดียวต่อคลาส +1
Nander Speerstra

Oldie แต่ Goldie! บันทึกวันของฉัน ขอบคุณสำหรับวิธีแก้ปัญหานี้ +1
Raistlin

13

หากคุณใช้ Spring Boot ให้เพิ่มการพึ่งพาไทม์ลีฟใน pom.xml ของคุณ:

    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring4</artifactId>
        <version>2.1.6.RELEASE</version>
    </dependency>

1
upvote การขาดการพึ่งพา Thymeleaf คือสิ่งที่ทำให้เกิดข้อผิดพลาดนี้ในโครงการของฉัน อย่างไรก็ตาม ff ที่คุณใช้ Spring Boot แล้วการพึ่งพาจะมีลักษณะเช่นนี้แทน:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
peterh


8

ในกรณีของฉันฉันกำลังทดลองใช้ Kotlin + Spring boot และฉันพบปัญหา Circular View Path คำแนะนำทั้งหมดที่ฉันได้รับทางออนไลน์ไม่สามารถช่วยได้จนกว่าฉันจะลองทำตามด้านล่าง:

แต่เดิมฉันใส่คำอธิบายประกอบคอนโทรลเลอร์โดยใช้ไฟล์ @Controller

import org.springframework.stereotype.Controller

จากนั้นฉันก็แทนที่@Controllerด้วย@RestController

import org.springframework.web.bind.annotation.RestController

และมันได้ผล


7

หากคุณไม่ได้ใช้ @RequestBody และใช้เพียง@Controllerวิธีเดียวที่ง่ายที่สุดในการแก้ไขปัญหานี้คือใช้@RestControllerแทน@Controller


นี่ไม่ใช่การแก้ไขตอนนี้มันจะแสดงชื่อไฟล์ของคุณแทนที่จะแสดงเทมเพลต
Ashish Kamble

1
ขึ้นอยู่กับปัญหาที่เกิดขึ้นจริง ข้อผิดพลาดนี้อาจเกิดขึ้นได้จากหลายสาเหตุ
MozenRath

4

เพิ่มคำอธิบายประกอบ@ResponseBodyในการส่งคืนวิธีของคุณ


โปรดใส่คำอธิบายว่าวิธีแก้ปัญหานี้จะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้อย่างไรและอาจส่งผลให้มีการโหวตเพิ่มขึ้น
Android

3

ฉันใช้ Spring Boot กับ Thymeleaf นี่คือสิ่งที่ได้ผลสำหรับฉัน มีคำตอบที่คล้ายกันด้วย JSP แต่ทราบว่าฉันกำลังใช้ HTML ไม่ JSP และเหล่านี้อยู่ในโฟลเดอร์src/main/resources/templatesเหมือนในมาตรฐานโครงการ Boot ฤดูใบไม้ผลิตามที่อธิบายไว้ที่นี่ นี่อาจเป็นกรณีของคุณ

@InjectMocks
private MyController myController;

@Before
public void setup()
{
    MockitoAnnotations.initMocks(this);

    this.mockMvc = MockMvcBuilders.standaloneSetup(myController)
                    .setViewResolvers(viewResolver())
                    .build();
}

private ViewResolver viewResolver()
{
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

    viewResolver.setPrefix("classpath:templates/");
    viewResolver.setSuffix(".html");

    return viewResolver;
}

หวังว่านี่จะช่วยได้


3

เมื่อเรียกใช้ Spring Boot + Freemarker หากหน้าปรากฏขึ้น:

หน้าข้อผิดพลาด Whitelabel แอปพลิเคชันนี้ไม่มีการแมป / error อย่างชัดเจนดังนั้นคุณจึงเห็นสิ่งนี้เป็นทางเลือก

ใน spring-boot-starter-parent 2.2.1.RELEASE เวอร์ชัน freemarker ไม่ทำงาน:

  1. เปลี่ยนชื่อไฟล์ Freemarker จาก. ftl เป็น .ftlh
  2. เพิ่มใน application.properties: spring.freemarker.expose-request-attributes = true

spring.freemarker.suffix = .ftl


1
เพียงแค่เปลี่ยนชื่อไฟล์ Freemarker จาก. ftl เป็น .ftlh ก็แก้ปัญหาให้ฉันได้
jannnik

ผู้ชาย ... ฉันเป็นหนี้คุณเบียร์ ฉันหายไปทั้งวันเพราะสิ่งที่เปลี่ยนชื่อนี้
julianobrasil

2

สำหรับ Thymeleaf:

ฉันเพิ่งเริ่มใช้สปริง 4 และไทม์ลีฟเมื่อฉันพบข้อผิดพลาดนี้ได้รับการแก้ไขโดยเพิ่ม:

<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
  <property name="templateEngine" ref="templateEngine" />
  <property name="order" value="0" />
</bean> 

1

เมื่อใช้@Controllerคำอธิบายประกอบคุณต้องมี@RequestMappingและ@ResponseBodyคำอธิบายประกอบ ลองอีกครั้งหลังจากเพิ่มคำอธิบายประกอบ@ResponseBody


0

ฉันใช้คำอธิบายประกอบเพื่อกำหนดค่า Spring web app ปัญหาแก้ไขได้โดยการเพิ่มInternalResourceViewResolverbean ในการกำหนดค่า หวังว่าคงจะเป็นประโยชน์

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.example.springmvc" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/jsp/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

ขอบคุณที่ทำงานได้ดีสำหรับฉัน แอพของฉันพังหลังจากอัปเกรดเป็น spring boot 1.3.1 จาก 1.2.7 และเป็นเพียงบรรทัดนี้เท่านั้นที่ล้มเหลว Registry.addViewController ("/ login") setViewName ("login"); เมื่อลงทะเบียน bean นั้นแอปจะทำงานอีกครั้ง ... อย่างน้อยการเข้าสู่ระบบก็ใช้งานได้
le0diaz

0

สิ่งนี้เกิดขึ้นเนื่องจาก Spring กำลังลบ "ค่ากำหนด" และต่อท้าย "ค่ากำหนด" อีกครั้งโดยทำให้เส้นทางเดียวกันกับคำขอ Uri

ที่เกิดขึ้นเช่นนี้ขอ Uri: "/ ค่ากำหนด"

ลบ "ค่ากำหนด": "/"

ต่อท้ายเส้นทาง: "/" + "ค่ากำหนด"

สตริงสิ้นสุด: "/ ค่ากำหนด"

สิ่งนี้กำลังเข้าสู่วงรอบซึ่ง Spring จะแจ้งให้คุณทราบโดยการโยนข้อยกเว้น

คุณควรตั้งชื่อมุมมองที่แตกต่างออกไปเช่น "PreferencesView" หรืออะไรก็ได้ที่คุณต้องการ


0

ลองเพิ่มการพึ่งพาคอมไพล์ ("org.springframework.boot: spring-boot-starter-thymeleaf") ให้กับไฟล์ gradle ของคุณ Thymeleaf ช่วยในการทำแผนที่


0

ในกรณีของฉันฉันมีปัญหานี้ขณะพยายามให้บริการเพจ JSP โดยใช้แอปพลิเคชัน Spring boot

นี่คือสิ่งที่ใช้ได้ผลสำหรับฉัน:

application.properties

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

pom.xml

ในการเปิดใช้งานการสนับสนุน JSPs เราจำเป็นต้องเพิ่มการพึ่งพา tomcat-embed-jasper

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

-2

อีกวิธีง่ายๆ:

package org.yourpackagename;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

      @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
            return application.sources(PreferenceController.class);
        }


    public static void main(String[] args) {
        SpringApplication.run(PreferenceController.class, args);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.