SpringMVC(三)
注解的引入
回顾
上一期我们写到原生版本的SpringMVC的执行流程
- 配置web.xml的DispatcherSrevlet和Spring容器
- Spring容器的配置文件使用bean注册处理器映射器,处理器适配器,和视图解析器
- 写一个类实现Controller表示这个就是Controller,并返回ModelAndView给视图解析器
显而易见这样我们能清晰的分析出SpringMVC的执行流程
用户的请求交给服务器,服务器会在启动的时候加载web.xml文件注册了DispathcerServlet并指出Sping容器的加载文件,这时前端处理器会根据请求进行映射,处理器映射的这个类在Spring容器中已经注册过了,映射器(HandlerMapping)会把请求映射为HandlerExecutionChain类型的handler对象交给这个中央控制器;然后中央处理器将handler对象作为参数传递给适配器(HandlerAdapter)的实例化对象,适配器对其进行处理,还会调用其他模型层最后返回ModelAndView给前端处理器。前端处理器调用视图解析器对视图名进行前缀和后缀拼接,并且前端处理器进行视图渲染(将模型装入view中)。
具体的流程我们是清楚了,但是实际开发我们不会采取这样的方法,太过于复杂,下面来介绍介绍注解开发
@Controller注解
使用这个注解直接表示这个类是Controller,不需要再实现controller接口并重写方法。
为了保证Spring能找到控制器类,还需要在Sping容器配置文件中添加扫描配置信息。如下:
(1)配置文件中引入约束spring-context
(2)使用<context:component-scan base-package="com.sang.controller"/>
这里的base-package表示的是包名,需要扫描的包名。
这里<context:component-scan base-package="com.sang.controller"/>
指定了com.sang.controller
这个包,在运行的时候,该包以及包下所有标注了注解的类都会被Spring所识别并处理。
- 控制器负责解析用户的请求并且将其转化为一个模型
- 其中规定了各样的复杂的访问应用程序的方式
对比:
使用注解的方式比原生的方法更加简单,同时,原生实现的实现类只能处理一个单一的请求动作,而基于注解的方式可以同时处理多个请求动作,更加灵活,节省开发者的效率
@RequestMapping注解
Spring容器通过@Controller注解找到相应的 控制器类后,还需要知道控制器内部是对每个请求是如何处理的,这就需要使用RequestMqpping注解类型。RequestMapping注解类型用于映射一个请求或者一个方法。
- 当标注在方法上时
表示该请求会直接映射成指定的value值,例如:
@RequestMapping(value= "/admin")
public String fun1(Model model){
model.addAttribute("msg","hello!");
return "hello";
}
当用户发送请求http://localhost:8080/springmvc-05/admin
DispatcherServlet会直接找项目下/admin对应的方法,这个方法中,传递了参数Model类型的数据,加入了一个字符串属性的值,方法最后返回一个字符串,而字符串返回到视图解析器中,视图解析器会根据规定的前缀和后缀来拼接字符串就像/WEB-INF/jsp/hello.jsp
,然后给前端控制器,随后前端控制将模型渲染在jsp或者其他的前端模板页面里,返回给用户。
- 当标注在类上时
@Controller
@RequestMapping(value= "/user")
public class MyCotroller{
@RequestMapping("/admin")
public String fun1(Model model){
model.addAttribute("msg","hello!");
return "hello";
}
}
当用户在地址栏上访问localhost:8080/springmvc-05/user/admin
同上原理一致,但是访问的请求在层级目录上分的很明确,用户在/user
下访问/admin
请求,中央处理器就会处理指定的“层级目录”下的请求方法,然后返回给视图解析器一个视图名称,最后解析为“WEB-INF/jsp/xxx.jsp"
让中央处理器去返回给用户。
@RequestMapping注解的属性
属性名 | 类型 | 描述 |
---|---|---|
name | String | 可选属性,用于为映射地址指定别名 |
value | String[ ] | 可选属性,用于指定映射的地址,用于映射一个方法或者一个类 |
method | RequestMethod[ ] | 可选的属性,用于指定请求的方式有GET,POST,DELETE,HEDA,OPTIONS,PUT,PATCH,TRACE |
params | String[ ] | 可选的属性,用于指定Request所传递的参数,必须有这些参数才可以通过这个方法进行处理 |
headers | String[ ] | 可选的属性,用于指定Request所传递的headers的值,必须有这些参数才可以通过这个方法进行处理 |
consumes | String[ ] | 可选的属性,用于指定处理请求的提交内容类型(Context-type) |
produces | String[ ] | 可选的属性,用于指定返回的内容类型,返回的内容类型必须是请求头中所包含的类型 |
啥也不写,默认的属性是value
@RequestMapping的组合注解
目的:简化HTTP方法的映射
- GetMapping:匹配Get方式的请求
- PostMapping:匹配Post方式的请求
- PutMapping:匹配Put方式的请求
- DeleteMapping:匹配Delete方式的请求
- PatchMapping:匹配Patch方式的请求
标注了@GetMapping的方法的请求如下
@GetMapping(value= "/admin")
public String fun1(Model model){
model.addAttribute("msg","hello!");
return "hello";
}
与@RequestMapping注解方法(如下)一致
@RequestMapping(value= "/admin",method=RequestMethod)
public String fun1(Model model){
model.addAttribute("msg","hello!");
return "hello";
}
@RequestMapping返回值(结果跳转方式)
在我们常见的SpringMVC的使用中,我们见过最多的是return一个字符串
如下:
@GetMapping(value= "/admin")
public String fun1(Model model){
model.addAttribute("msg","hello!");
return "hello";
}
这里String类型的返回值会被"Servlet"传递到视图解析器中,视图解析器得到字符串会拼接前缀和后缀,成为“/WEB-INF/jsp/hello.jsp”,然后ViewResolver就会把该逻辑视图路径解析为真正的View视图对象,然后通过View的渲染,将最终结果返回给中央处理器,然后呈现给用户
但是还有另外的使用方法:
ServletAPI
通过设置ServletAPI , 不需要视图解析器 .
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//转发
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
我们的Controller里的标注了注解的方法其实也就相当于一个个的Servlet,直接通过Servlet的API进行视图转发,这时不需要制图解析器,不信可以注释掉MVC配置文件中的视图解析器。
转发和重定向
测试前,需要将视图解析器注释掉
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.可以重定向到另外一个请求实现 .
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do为另一个请求/
}
}
RestFul风格
- 概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
- 功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET
使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
-
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get
http://localhost/item/queryItem.action?id=1
查询,GEThttp://localhost/item/saveItem.action
新增,POSThttp://localhost/item/updateItem.action
更新,PUThttp://localhost/item/deleteItem.action?id=1
删除,GET或POST -
RestFul风格
使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!http://127.0.0.1/item/1
查询,GEThttp://127.0.0.1/item
新增,POSThttp://127.0.0.1/item
更新,PUThttp://127.0.0.1/item/1
删除,DELETE
演示
Controller层
@GetMapping(value="/admin/{a}/{b}")
public String test(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg",a+b);
return "hello";
}
访问http://localhost:8080/springmvc-05/admin/1/5
结果如下:
这里@PathVariable int a,@PathVariable int b
会将URL里的参数赋值,最后在model中加入参数msg的值是a+b,呈现给用户。
- RestFul风格的好处:URL更加简洁,获取参数更加方便,框架会自动进行类型转换。
- 通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/commit/1/a,则路径与方法不匹配,而不会是参数转换失败。
所有的地址栏请求默认都会是 HTTP GET 类型的。