SpringMvc是替换servlet的一种Web(表现)层框架
使用:
1 . 导入javax.servlet-api和spring-mvc依赖
(注意在servlet依赖没添加配置<scope>provided</scope>,否则会有报错 A child container failed during start )
2 . 创建controller包,下设SpringMvc控制器类,类加注解@Controller(用于声明SpringMvc控制器,并将这个类定义为Bean类似@Component系列四个),类内写自定义方法,return后的值将输出到网页
方法添加@RequestMapping("/自定义名")注解,未来在网址栏输入这个路径进行访问,添加@ResponseBody注解,指明将return后的整体作为响应内容反馈给请求方
关于@RequestMapping内路径配置的问题:
为了防止不同的controller类内配置了相同的路径,一般在controller内配置的路径前增加前缀,可以在类的上方增加@RequestMapping注解,在括号内添加一个这一类统一的前缀(如 : "/user")
在网址栏请求这个路径时将这个前缀添加上即可
get请求和post请求参数传递问题:
1 . 当需要在网址栏传值时,只需要在设置了路径的这个方法内添加 形参 进行接收即可
2 . 当形参名和网址栏输入的变量名不一致时,在形参前添加@RequestParam注解,在注解的括号内填入地址栏输入的值的名称,每一个形参对应一个@RequestParam注解
3 . 当形参设置成一个pojo对象时,在地址栏传值时可以直接向pojo类的变量传值
4 . 当形参是一个数组对象时,地址栏填多个变量名为形参数组名的变量,这些变量均会填充入数组内
5 . 当形参是一个集合时,为了让其底层的执行过程是创建一个集合然后向李传数而不是创建集合类【经典的NoSuchMethodException错误】,向这个类内填充参数,添加@RequestParam注解即可
6 . 对日期类型(Date)形参进行地址栏get post传值时,要么按照2020/12/12这样的斜线隔离的格式,要么在Date形参前添加@DateTimeFormat注解,注解内pattern=" “ 双引号内填你即将传入的日期格式
(比如:yyyy-MM-dd)
需要接收json参数时:
1 . 导入jackson-databind依赖
2 . 在SpringMvc对应的config类内添加@EnableWebMvc注解,开启由Json数据向对象转化的过程
3. 使用list集合接收json参数时,需要在list前添加@RequestBody注解(凡是接收Json数据均需要使用这个注解)(注意和@ResponseBody注解区分,@RequestBody注解在一个方法上只能使用一次【该操作规避了经典的NoSuchMethodException】
4 . 返回json数据时,方法上添加@ReponseBody注解,直接return需要return的对象或者其他类型的数据即可,return后填入的数据会自动转成json格式
跳转页面时:(莫名原因,跳转页面时,不能在类上添加@RequestMapping注解)
在配置路径的方法的return后面添加页面名称(如:index.jsp)
(注意:不能添加@ResponseBody注解,不然会将return后的文件名看作字符串)
3 . 让config配置类的组件扫描@ComponentScan扫描到controller包
4 . 新设置一个config类,让这个类继承 AbstractDispatcherServletInitializer 父类,重写父类的三个方法:
createServletApplicationContext:加载SpringMvc容器配置
创建AnnotationConfigWebApplicationContext对象,
调用对象的register方法,方法括号内填扫描过controller包的那个config配置类的类名字节码(类名.class)
将这个对象return
getServletMappings:声明哪些请求归SpringMvc管理
return new String[]{"/"}; 将所有请求交给SpringMvc管理
createRootApplicationContext:加载Spring容器配置
工作流程:
启动服务器初始化的过程:
1 . 加载继承AbstractDispatcherServletInitializer父类的config类,初始化Bean容器,通过createServletApplicationConfig方法创建AnnotationConfigWebAapplicationContext对象,将这个对象加载到web容器的ServletContext内
2 . 第一步的方法内的register方法使得SpringMvc加载了对应的那个config类,这个类内配置了针对controller的组件扫描
3 . 第二步的自建扫描启动,将controller类下的@Controller标注的控制器类进行Bean的实例化(实例化的Bean存在于AnnotationConfigWebApplicationContext内)
4 . 第三步方法上注解的@RequestMapping注解的路径被读取,@ResponseBody注解使得return的值回馈在前面路径对应的网页上
5 . 执行第一步对应的那个类的getServletMapping方法,确定将哪些请求归属SpringMvc管理
单次请求的执行过程:
1 . 在网址栏输入网址请求(@RequestMapping注解配置的路径)
2 . Web容器发现getServletMapping方法规定了该请求归属SpringMvc管理,对请求路径进行解析
3 . 通过路径执行对应的 配置了@RequestMapping的方法 ,发现方法标注有@ResponseBody注解,于是将return后的值打印在网页上
关于Spring和SpringMvc运行的一些冲突:
Spring的配置一般是加载Servlet等等一系列所有包,但是controller包需要让SpringMvc加载,要想办法阻止Spring扫描到controller包
方法一:配置Spring1的扫描时精准的配置扫描的包(Servlet,Dao),不让他扫描到controller包
方法二:想办法将controller包排除出Spring的扫描加载范围
在Spring的config类内的 @ComponentScan注解 内excludeFilters里配置不扫描的controller
具体实现:excludeFilters = @CompnanetScan.filter(type = FilterType.ANNOTATION,classes = Controller.class)
配置按注解类型排除的过滤器class后填注解类字节码(注解名.class)
(类似的insertFilter配置则是追加需要配置的类)
方法三:不再区分Spring的环境和SpringMvc的环境,在继承AbstractDispatcherServletInitializer父类的config类内的createRootApplicationContext方法内
像createServletApplicationContext方法一样创建相同的对象,register进Spring相关配置的config类,让初始化时就导入Spring的容器
于是为了简化继承AbstractDispatcherServletInitializer的config类的书写,可以让这个类继承AbstractAnnotationConfigDispatcherServletInitializer类,这个类下的三个方法:
getServletConfigClasses
在return内返回SpringMvc对应的config类字节码文件
getRootConfigClasses
在reurn那日返回Spring对应的config类字节码文件
(return new Class[]{Springconfig.class};
getServletMappings
与继承父类时的 getServletMappings方法相同,声明哪些请求归SpringMvc管理
return new Class[]{"/"}; 所有请求均归SpringMvc管理
当需要访问的页面请求被SpringMvc拦截下时:
原因:"/"使得所有的请求均被SpringMvc拦截
解决:配置拦截器(只是方法之一)
新建一个config类,继承WebMvcConfigurationSupport接口
重写接口的addResourceHandlers方法,
调用形参ResourceHandlerRegistry的addResourceHandler方法。方法内填入需要放行的地址栏输入的路径和访问的具体路径(webapp下指向页面的路径)
(这样,当地址栏访问addResourceHandler方法内第一个路径时,这个请求不再被SpringMvc拦截处理,而是访问方法内填入的第二个路径指向的页面)
(将N个页面解除SpringMvc的拦截要调用N个addResourceHandler方法,分别填入放行路径和实际访问路径)
当出现中文乱码问题时,我们一般在继承了AbstractDispatcherServletInitializer的这个类内添加 字符过滤器
首先重写getServletFilters方法,然后创建一个CharacterEncodingFilter对象,调用这个对象的setEncoding方法传入UTF-8,再将这个对象return,即可解决乱码问题
(现实情况是解决了post和get请求内给标注了路径的方法的形参传中文值出现错误的情况)
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
REST风格:
1 . 书写简化 2 . 隐藏资源访问行为
网址栏访问格式:
区别于正常的路径后添加 ?变量名=值 的格式,使用 路径/值
such as:
http://localhost:8080/user/14 此格式意为/user路径下的方法,形参传值14
使用RUST风格的方法的格式:
@RequestMapper后的路径不再体现出具体业务的内容,而是填写本来在类上方@RequestMapper内填写的用来和其他controller类区分的那个路径,在路径后填写 /{ } 大括号内填写形参名
然后在@RequestMapper内配置method参数,此处填写 http请求动作 (SpringMvc支持的 get put post delete)
形参前添加@PathVariable 注解,接收路径参数(即 路径/ 后的参数)
示例:
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println(id);
System.out.println("user delete ...");
return "user delete ...";
}
RESTful简化开发:
1 . 将每个方法的@RequestMapping内都要重复填写的 路径名 填写到类上方,这样每个controller类内的方法都只需要在@RequestMapping配置method和value的 /{}形参名
2 . 如果所有的方法都使用@ResponseBody,可以将这个注解提前到类上方,然后可以进一步简化,将@ResponseBody注解和@Controller注解合并成一个注解 @RestController
3 . 每个方法上方的@RequestMapping注解可以用 @http请求Mapping 如,post请求对应的就是@PostMapping注解,省略了@RequestMapping内method属性的配置
(如果原本的@RequestMapping内有关于形参的 /{} 相关配置,在@http请求Mapping内添加即可)