SpringBoot+Vue.js+分布式组件全栈开发训练营(视频教学版)
上QQ阅读APP看书,第一时间看更新

2.4 编写控制器类

启动Spring Boot后,该项目就会在默认的8080端口监听请求。一旦有请求到达,控制器类就会接收、匹配并处理该请求。

2.4.1 用@Controller注解定义控制器类

本小节将新建名为ControllerDemo的Maven项目,其中的pom.xml和启动类与之前2.3.1小节的StarterDemo很相似,这部分代码读者可参考之前的讲解。

在该项目中将新建Controller.java类作为控制器,该控制器类和启动类的目录层次关系如图2.6所示。从中可以看到,启动类处在prj这个包之下,而控制器类则处于prj.controller这个包之下。

图2.6 控制器类和启动类的层次关系示意图

之前已经提到,由于启动类中的@SpringBootApplication注解包含@ComponentScan注解,因此在启动时会扫描本包(这里是prj包)和子包(包括prj.controller包)下的程序,这样就会扫描到并识别控制器类。根据此特性,在实际项目中一般会把控制器类放在和启动类同级或下级的包里。具体控制器类Controller.java的代码如下:

控制器类的类名可以随便起,但需要用第4行的@RestController注解标识本类是控制器类。

在控制器类中,处理请求的方法名可以随便起,但需要在诸多方法前像第6行和第10行那样用@RequestMapping注解标识本方法可以处理哪种格式类型的URL,比如第7行的indexPage方法可以处理/index格式的请求,而第11行的welcomePage方法可以处理/welcome格式的请求。

在控制器的方法中,可以通过return字符串的形式返回该方法的处理结果,如第8行和第12行所示。写完控制器类的代码后,启动该项目,并在浏览器中输入http://localhost:8080/index。

这里的localhost:8080是Spring Boot项目所监听的IP地址和端口号,而/index则是请求的URL,根据控制器类Controller.java中第6行代码的定义,该/index请求会被第7行的indexPage方法处理,根据第8行的返回结果,该http://localhost:8080/index请求能在浏览器中得到“index”的输出。

同理,如果在浏览器中输入http://localhost:8080/welcome,就能看“welcome”的输出,如图2.7所示。

图2.7 控制器范例的运行效果图

从本范例中,读者能看到控制器类的作用:接受请求,并根据方法的@RequestMapping注解匹配请求,如果能匹配上,就用该方法的代码来处理并返回请求,也就是说,控制器类承担着“前端代码”和“后端业务处理逻辑”之间的桥梁作用。

2.4.2 用@RequestMapping映射请求

在2.4.1小节给出的控制器范例中,读者已经看到,用@RequestMapping注解可以定义控制器方法能映射处理的请求,该注解有如表2.2所示的常用参数。

表2.2 @RequestMapping注解常用参数一览表

为了演示@RequestMapping注解映射URL请求的做法,需要在上文所创建的ControllerDemo项目中新建一个名为ControllerForReq的控制器类,该类的代码如下:

由于第10行@RequestMapping注解的value参数是/testValue,因此第11行定义的testValue方法能处理/testValue格式的请求,注意这里value参数的写法等同于第9行。启动该Spring Boot项目后,在浏览器中输入http://localhost:8080/testValue,就能在浏览器中看到testValue的字样。

在第16行和第21行定义的两个方法中,通过@RequestMapping注解的method参数定义了这两个方法分别能映射method为GET和POST的方法。

如果在浏览器中输入http://localhost:8080/demoMethod,由于该URL能被第15行的@RequestMapping注解映射到,且该请求是GET类型的,因此会被第16行的testGetMethod方法所处理,并在浏览器中得到“The method is GET”的输出结果。

如果在浏览器中输入http://localhost:8080/testPostMethod,由于该请求是GET类型的,而不是POST类型的,无法被第21行的testPostMethod方法及其他方法处理,因此该请求会得到如图2.8所示的结果,也就是说,该请求无法匹配到对应的控制器方法,所以无法得到处理。

图2.8 请求无法被处理

根据第25行的定义,第26行demoParams方法能处理/demoParams格式的请求,且该请求需要包含id和name的参数,且name的值必须是Peter,所以该方法只能处理如下格式的URL:

http://localhost:8080/demoParams?id=123&name=Peter

其中id参数的值可以随便输入,但name参数的值必须是Peter,如果在浏览器中输入上述请求,则能看到“demoParams”的输出结果。

如果URL正确,但参数输入错误,比如http://localhost:8080/demoParams,就能看到如图2.9所示的错误结果,从中能看到错误的返回码是400,表示参数格式错误。

图2.9 输错参数导致400错误

2.4.3 从请求中读取参数

在用@RequestMapping注解把URL请求映射到控制器中的方法上时,会通过params等方式携带参数,对此可以在控制器的方法中用@PathVariable和@RequestParam注解对应地读取参数。

在如下的ControllerForPath.java控制器范例中将演示这一做法,具体的代码如下:

在第9行getPersonByID方法所对应的@RequestMapping注解中定义了该方法能处理/getPersonByID/{id}格式的请求,其中{id}表示该URL传入的名为id的参数。

所以在第9行的方法中,需要在String id前加上@PathVariable注解,说明url中传入的id参数将作为该方法的id参数传入getPersonByID的方法中。

如果在浏览器中输入http://localhost:8080/getPersonByID/001,则在该URL中,id参数所对应的值是001,因此该URL被getPersonByID方法处理时,001会以String类型的id参数的方式被getPersonByID方法接收并处理,对应地,根据第10行的返回语句,该请求能得到“The ID is:001”的输出语句。

根据第13行@RequestMapping注解的定义,第14行的getPersonByIDAndName方法能处理的URL格式是/getPersonByIDAndName/{id}/{name},其中{id}和{name}也是该URL对应的参数,所以在第14行的方法中,需要用@PathVariable String id,@PathVariable String name的形式把URL中包含的id和name参数传入方法中。

对应地,如果在浏览器中输入http://localhost:8080/getPersonByIDAndName/1/Peter的请求,根据第15行语句的定义,能在浏览器中看到“The ID is:1, name is:Peter”的输出结果。

和之前方法不同的是,在第19行的getAccountByID方法中,是用第18行@RequestMapping注解params的形式传入参数id的,所以这里需要在getAccountByID方法的String id参数前加入@RequestParam注解,指明由@RequestMapping注解params所传入的id参数将被第19行的id参数所接收并处理。

对应地,如果在浏览器中输入http://localhost:8080/getAccountByID?id=1的请求,能看到输出结果是“The Account ID is:1”,由此能看到,第18行由params传入的参数id被@RequestParam注解成功地传递到方法中。

这里来总结一下在请求中读取参数的做法。

(1)如果参数写在URL请求中,比如/getPersonByID/{id},那么可以通过@PathVariable注解来读取参数。相反,如果参数是由@RequestMapping注解中的@Params传入的,那么需要用@RequestParam来传递参数。

(2)@PathVariable和@RequestParam注解均作用在方法的参数前,并且这两个注解所作用的参数名必须和URL请求所携带的参数名保持一致,比如/getPersonByID/{id}请求中参数名是id,@PathVariable注解所作用的方法参数名也得叫id,否则就会出错。

2.4.4 用produces参数返回JSON格式的结果

在之前的范例中,读者在浏览器中看到的输出结果都是文本类型的。在一些场景中,需要把输出内容转换成JSON格式并输出,对此可以通过@RequestMapping注解中的produces参数来实现。

具体可以在2.4.1小节创建的ControllerDemo项目中新建一个名为ControllerForJSON.java的控制器类,并写入如下代码:

根据第8行demoJSON方法之前的@RequestMapping注解定义,该方法能处理/demoJSON格式的请求,并且这里还通过@RequestMapping注解的produces参数定义了该方法的返回结果将会被转换成JSON格式。

再来看一下第9行和第13行的方法主体,在其中创建了名为accountHM的HashMap,并通过第10~12行的方法向该HashMap中插入了若干数据,最后返回了HashMap类型的accountHM对象。

对应地,如果在浏览器中输入http://localhost:8080/demoJSON请求,那么能看到如图2.10所示的结果。从中可以看到,虽然demoJSON方法返回对象的类型是HashMap,但根据第7行produces参数的定义,该对象会被转换成JSON格式并输出。

图2.10 转换成JSON格式后输出