了解SpringMVC(二)
上一篇文章让我们初步的了解了Spring MVC与Servlet&JSP处理请求的不同,以及简单的学习了Spring MVC处理请求的方式。这一章我们来学习些它的常用的知识点。
常用知识点
定义Controller
@Controller
public class OwnerController {
@GetMapping("/hello/{petId}")
public String hello() {
// ...
}
}
处理请求
在Controller的方法上添加@RequestMapping
注解
@RequestMapping("/hello")
public String hello() {
return "hello";
}
获取请求参数
请求参数可以直接定义到方法参数里,并通过@RequestParam("key")
注解修饰参数,这样SpringMVC会自动解析请求中的参数给你填充到方法参数中。
**注意:**此注解修饰的参数默认是必传的,如果请求中没有此参数会直接报错,可以通过设置此注解的required
属性为false
解决
@RequestMapping("/login")
public String test(int age, String name, @RequestParam(value = "nickname", required = false) String nickName, Model model) {
System.out.println("login, age: " + age+", name: " + name+", nickName: " + nickName);
// 放到request作用域中,可以在前端获取
model.addAttribute("msg", age);
return "main";
}
JDK1.8以后我们也可以通过添加编译参数
-parameters
参数告诉编译器在编译时保留方法参数名,这样如果请求中参数名与方法定义的参数名对应时,可以不用显示添加@RequestParam注解
获取请求头参数
如果想获取请求头中携带的参数,springmvc给我们提供了一个@RequestHeader
注解,此注解和@RequestParam
一样默认参数必传,同样可以选择使用required
属性解决,使用方式如下:
@RequestMapping("/header")
public String getVarFromRequestHead(@RequestHeader(value = "sname", required = false) String sname, Model model) {
model.addAttribute("sname", sname);
System.out.println("sname: " + sname);
return "hello";
}
一般请求头参数的用法测试需要用到专门的发送请求的工具,我使用的是PostMan这款软件,用法是新建请求后在Head里添加参数sname
,访问地址是:http://localhost:8080/header
获取URI中的变量
这个作用通常用于restFul服务,可以通过@PathVariable
注解获取到请求uri中的变量
@RequestMapping("/path_var/{sname}/{age}")
public String getVarFromUri(@PathVariable("sname") String sname, @PathVariable("age") Integer age, Model model) {
model.addAttribute("sname", sname);
model.addAttribute("age", age);
System.out.println("sname: " + sname + "age: " + age);
return "hello";
}
获取Cookie数据
Cookie中的数据同样可以获取到,只需要一个@CookieValue
注解就能做到,示例如下:
@RequestMapping("/cookie/attr")
public String getAttrFromCookie(@CookieValue("sname") String sname, Model model) {
model.addAttribute("sname", sname);
System.out.println("sname: " + sname);
return "hello";
}
测试我们还是选择使用刚才提到的postMan测试工具,新建请求后,添加一个Cookie后只需要修改cookie的key和value就行,访问路径:http://localhost:8080/cookie/attr
获取作用域数据
这里的作用域主要指request 作用域和session作用域,不包括application作用域
获取request作用域数据
可以使用@RequestAttribute
注解获取作用域中的对应属性的值,示例:
@RequestMapping("/scope/request/attr")
public String getAttrFromScope(@RequestAttribute(value = "sname", required = false) String sname, Model model) {
model.addAttribute("sname", sname);
System.out.println("sname: " + sname);
return "hello";
}
这个测试就需要在jsp页面添加一个属性到request作用域中
<% request.setAttribute("sname","张三"); %>
访问路径:http://localhost:8080/scope/request/attr
获取session作用域数据
可以使用@SessionAttribute
注解获取作用域中的对应属性的值,示例:
@RequestMapping("/scope/session/attr/")
public String getAttrFromScope(@SessionAttribute(value = "sname", required = false) String sname, Model model) {
model.addAttribute("sname", sname);
System.out.println("sname: " + sname);
return "hello";
}
这个测试就需要在jsp页面添加一个属性到request作用域中
<% session.setAttribute("sname","张三"); %>
访问路径:http://localhost:8080/scope/session/attr
使用提前初始化的数据
初始化数据、参数,在方法上添加@ModelAttribute
注解。
/**
* 使用一个Model中提供的Map
*/
@ModelAttribute
public Model prepareData() {
Model model = new ConcurrentModel();
model.asMap().put("sname", "sss");
return model;
}
/*
或者使用一个HashMap
@ModelAttribute
public Map<String, String> prepareData() {
Map<String, String> data = new HashMap<>();
data.put("sname", "张四丰");
return data;
}*/
使用当前Controller中通过@ModelAttribute注解预初始化的数据
@RequestMapping("/model/attr")
public String testModelAttr(@ModelAttribute Model model, Model modelToView) {
modelToView.addAttribute("sname", model.asMap().get("sname"));
System.out.println("model key: sname->" + model.asMap().get("sname"));
return "hello";
}
/*
直接使用HashMap的方式
@RequestMapping("/model_attr")
public String testModelAttr(@ModelAttribute Map<String, String> data, Model model) {
System.out.println("model key: sname ->" + data.get("sname"));
model.addAttribute("sname", data.get("sname"));
return "hello";
}*/
**注:**如果使用Model提供的asMap方法,则测试时的第二个Model参数不能省略,因为使用@ModelAttribute
注解后Model会变成一个只具有Map功能的Model,不再具有与视图解析器传递参数的功能,因此,此时如果想把数据放到作用域中传到前端,则只能再加一个Model参数。
测试的访问路径:http://localhost:8080/model/attr
请求参数自动绑定到对象中
如果RequestMapping方法的参数中是一个自定义的对象,Spring会调用DataBinder自动将请求中的参数注入到对象的同名属性中。
使用示例:
@RequestMapping("/test/bind_obj")
public String testBindObject(Student student, Model model) {
System.out.println("testBindObject, student: " + student);
model.addAttribute("msg", student);
return "main";
}
访问地址:
http://localhost:8080/test/bind_obj?sname=张三&age=34&id=2
通用无逻辑页面跳转
如果我们有些请求只是想跳转页面,不需要来后台处理什么逻辑,我们无法在Action中写一个空方法来跳转,直接在中配置一个如下的视图跳转控制器即可(不经过Action,直接跳转页面)
<mvc:view-controller path="/" view-name="home"/>
重定向
请求处理方法返回的视图名前添加redirect前缀
内部地址:
return "redirect:/myapp/some/resource"
外部地址:
return "redirect:https://myhost.com/some/arbitrary/path"
请求处理方法返回RedirectView对象
内部地址:
return new RedirectView("/myapp/some/resource");
外部地址:
return new RedirectView("https://myhost.com/some/arbitrary/path");
请求转发
请求处理方法返回的视图名前添加forward前缀
示例:
return "forward:/WEB-INF/pages/main";
请求处理方法返回InternalResourceView对象
直接返回一个页面的名称,默认会使用forward方式通过视图解析器转发到对应的页面,示例:
return "main";
放行静态资源
默认Tomcat是可以处理静态资源的(通过DefaultServlet处理,在%tomcat_home%/conf/web.xml
中),但是我们配置了SpringMVC后, 往往会将DispatcherServlet的拦截路径设置成"/"
,会将Tomcat中默认的DefaultServlet覆盖掉,所以静态资源也会进入DispatcherServlet中处理,而默认DispatcherServlet中是没有处理静态资源相关的逻辑, 所以访问静态资源就会报404
第一种解决方式:
<mvc:default-servlet-handler />
将静态资源交还给容器来处理(比如说Tomcat就是让DefaultServlet来处理)
- 优点:配置简单
- 缺点:只能访问web根目录下公开的静态文件, WEB-INF、类路径下都无法访问
第二种解决方式:
<mvc:resources mapping="/static/views/**" location="WEB-INF/views/,classpath:/static/" />
放行静态资源, mapping匹配你请求的URI; location指定静态资源相对位置,会将mapping中通配部分的内容拼到location指定的相对位置后面
到此,我们已经基本上可以处理前后端交互时的常见请求了,那么Spring MVC就这点东西了吗?当然不可能,所以下一章就是一些进阶的知识了。