添加Spring配置类
package cn.codingfire.springmvc.config; import org.springframework.context.annotation.Configuration; @Configuration public class SpringConfig { }
这个我们应该很熟悉了,上一篇也已经讲过了。
添加Spring MVC配置类
package cn.codingfire.springmvc.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @ComponentScan("cn.codingfire.springmvc") public class SpringMvcConfig implements WebMvcConfigurer { }
目的是扫描对应包下的文件,并引入了Spring MVC配置。
创建初始化类
此类需要继承自AbstractAnnotationConfigDispatcherServletInitializer,且必须重写父类三个抽象方法,其实在继承后,可以根据快捷键自动生成。
package cn.codingfire.springmvc; import cn.codingfire.springmvc.config.SpringConfig; import cn.codingfire.springmvc.config.SpringMvcConfig; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { //返回自己配置的Spring相关的配置类 return new Class[] {SpringConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { //返回自己配置的Spring MVC相关的配置类 return new Class[] {SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { //返回由Spring MVC框架处理的路径 return new String[] {"*.page"}; } }
这里解释下为什么这么做,俩字,规定!就像我们要按照语法写Java一样,这里就是要按照这样的方式来写。
*.page这里就是用了一个不正常的扩展名,因为怕冲突,我们可以随便配,只要不冲突就行。
创建控制器类
package cn.codingfire.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { //http://localhost:8080/springmvc_war_exploded/login.page @RequestMapping("/login.page") @ResponseBody public String login() { return "login page"; } }
@RequestMapping("/login.page")注解,通常添加在类上,用于配置请求路径的前缀部分,也使用produces属性配置此控制器类中所有处理请求的方法响应时的文档类型,例如在类上配置为@RequestMapping(value="xxxxx", produces="application/json; charset=utf-8")。
@ResponseBody 注解,用于响应正文,可添加在处理请求/处理异常的方法之前,将作用于对应的方法,或添加在类之前,将作用于类中所有处理请求/处理异常的方法。
@Controller注解,组件注解,添加在类的声明之前,表示此类是组件类,应该添加在控制器类上。
从这里开始,我们真正接触接口的开发了,只不错这里还不是我们传统意义的接口,只因为返回不是json格式,这个不急,我们后面会讲。
开始进行测试
以上几步做完之后,我们就可以在浏览器输入链接,看看页面请求服务器后能不能返回给我们一个显示login page的页面,经测试,完全无误。
这里又个很有意思的东西,如果返回中文,则会在浏览器中出现乱码,这是因为某些版本的Spring MVC默认的字符编码是ISO-8859-1,只支持ASCII字符,后续会解决这个问题,大家稍安勿躁。
Spring MVC框架的功能
@RequestMapping注解
上面已经简单对@RequestMapping注解做过说明,但@RequestMapping注解远不止此,在以后的开发生涯,你将无法甩开@RequestMapping注解,因为它真的很重要。下面,我们就来说说@RequestMapping注解可以做什么。
@RequestMapping注解的主要作用是配置请求路径和相应方法的映射关系,在上例中,大家已经看到了它的基础用法。除了配置在方法前,还可以配置在类之前,表示给当前路径额外增加一小段路径,举例说明:
@Controller @RequestMapping("/user") public class UserController { //http://localhost:8080/springmvc_war_exploded/login.page @RequestMapping("/login.page") @ResponseBody public String login() { return "login page"; } }
添加了“/user”后,我们的请求路径就要变了:
原来的路径:http://localhost:8080/springmvc_war_exploded/login.page
新的路径:http://localhost:8080/springmvc_war_exploded/login.pagehttp://localhost:8080/springmvc_war_exploded/user/login.pagehttp://localhost:8080/springmvc_war_exploded/login.page
"/user"你当然可以写的更长一些,比如"/user/header",只要有利于你的开发。“/”可以不加,系统会自动补上,但是有个“/”时,中间分隔的不能省略,若是写了“//”,只会有一个生效。
一般在项目中,我们会针对不同的模块给出不同的模块名字,以方便开发者区分接口的所属部分。
RequestMapping还可以设置其他的一些参数:
method:请求方式
@RequestMapping(value = "/login.page", method = RequestMethod.POST)
可以指定请求的方式是get?还是post?抑或是其他的类型,一般来说,实际开发中,我们很少在方法上直接使用@RequestMapping,再来指定请求的类型,因为有更简便的方式,比如@PostMapping等。只有同时允许多种请求方式,我们才会这么用,但开发者一般不会这么做,这种用法多年来我也见过,但确实不多。
关于请求方式,共有GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE几种。里面大多我们是不常用的。
一旦指定了类型,使用错误的请求方式,将会报405错误。
headers:请求头
params:请求参数
consumes:请求文档类型
produces:响应文档类型
@RequestMapping(value = "/login.page", produces="text/html; charset=utf-8")
produces我们用来显示的指定响应文档的类型,它直接决定返回的数据是json类型?还是我们目前的字符串类型。值得一提的是,这个添加解决了我们上面返回中文乱码的问题,因为我们指定了utf-8格式。
@ResponseBody注解
@ResponseBody是响应正文,它响应的内容将直接展示在客户端,没有配置的时候,将直接显示为视图组件的名称,也就是我们常说的jsp文件,但这并不是前后端分离的思想,早起用的很多,如今jsp几乎已经没有公司在使用了。我们现在多采用前后端分离的做法。
@ResponseBody注解可以添加在方法上,也可以 添加在类上,在类上则作用于全部的方法。
前后端分离好处是,一个接口,多端使用,而不需要后端写好几套接口供给不同的端来使用,大家应该是比较熟悉的。所以,Spring MVC内置了转换器,将方法的返回值转换为响应到客户端的数据(并补充其它必要数据),返回值不同,则使用的转换器也不同。比如我们刚刚提到的中文乱码问题。
这里我们采用String类型作为返回值,实际开发中,我们绝对不会这么做,因为一个接口不仅仅是返回一个数据,还包括是否成功,成功失败的message,相应的数据,这时String类型已经无能为力,你说String可以吗?也可以,但是会出现后端转换String难,客户端String转换json难的问题,这就浪费了时间,完全没必要。
这里,我们推荐一个依赖来解决这个问题:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency>
添加到pom文件中,记得拉一下依赖,下载下来。
jackson-databind依赖项中有个转换器,当Spring MVC调用的处理请求的方法的返回值是Spring MVC没有匹配的默认转换器时,会自动使用jackson-databind的转换器,而jackson-databind转换器会解析方法的返回值,并将其处理为JSON格式的字符串,在响应头中将 Content-Type设置为application/json。这里用到了RequestMapping中的header属性。
注意啦,Spring MVC项目中,还需要在Spring MVC的配置类上添加 @EnableWebMvc注解,否则响应时将导致406错误。