一 Requestmapping
映射多个 URI
value 和 path 属性作用相同,可以互换。仅有一个属性,可以省略。
@RequestMapping(value = {
"/a","/b","/c"
})
public String multi(){
return "multi";
}
method属性
可以接收一个或多个RequestMethod枚举
@RequestMapping(value = "/post",method = RequestMethod.POST)
public String post(){
return "post";
}
@RequestMapping(value = "/get",method = RequestMethod.GET)
public String get(){
return "get";
}
@RequestMapping(value = "/getOrPost",method = {RequestMethod.GET,RequestMethod.POST})
public String getOrPost(){
return "getOrPost";
}
params属性
该属性表示请求参数,需要请求中必须传这些参数(放在url或者请求体中都可以)
@RequestMapping(path = "/login", params={"username=kolbe","password=123456"})
public String login() {
return "success";
}
headers 属性
@RequestMapping(path = "/header", headers="Accept-Language=zh-CN")
public String header() {
return "success";
}
@RequestMapping(path = "/header2", headers={"Accept-Language=zh-CN","Accept=text/html"})
public String header2() {
return "success";
}
支持ant风格
Ant 风格资源地址支持 3 种匹配符:
- ?:匹配文件名中的一个字符 –
- *:匹配文件名中的任意字符 –
- **: 匹配多层路径
@RequestMapping(path = "/ant/*")
public String ant() {
return "success3";
}
@RequestMapping(path = "/ant/?")
public String ant1() {
return "success1";
}
@RequestMapping(path = "/ant/**")
public String ant2() {
return "success2";
}
根据测试优先度排名:?>*>**
二PathVariable
是 Spring3.0 新增的功能
//@PathVariable可以用来映射URL中的占位符到目标方法的参数中
@RequestMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id)
{
System.out.println("testPathVariable:"+id);
return SUCCESS;
}
三 rest风格
由于浏览器表单只支持 GET 和 POST 请求,为了实现 DELETE 和 PUT 请求,Spring 为我们提供了一个过滤器org.springframework.web.filter.HiddenHttpMethodFilter
,可以为我们将 GET 和 POST 请求通过过滤器转化成 DELETE 和 PUT 请求。
在 web.xml 中配置过滤器
<!-- 配置 org.springframework.web.filter.HiddenHttpMethodFilter 过滤器 -->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
由于浏览器表单无法发送 DELETE 和 PUT 请求,所以为了让 HiddenHttpMethodFilter 识别请求的方法,需要在表单中添加一个隐藏域,名字为_method
值为 DELETE 或 POST 或PUT,修改后 index.jsp 页面代码如下:
<form action="user" method="post">
<input type="hidden" name="_method" value="POST"/>
<input type="submit" value="Test Rest POST"/>
</form>
<!-- 删除id为1的user -->
<form action="user/1" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="Test Rest DELETE"/>
</form>
<!-- 更新id为1的user -->
<form action="user/1" method="post">
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="Test Rest PUT"/>
</form>
四 RequestHeader、CookieValue
@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。
@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
@CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。
@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {
//...
}
五 sessionattributes
参考:springmvc基础知识(19):@SessionAttributes注解的使用
- 若希望在多个请求之间共用数据,则可以在控制器类上标注一个 @SessionAttributes,配置需要在session中存放的数据范围,Spring MVC将存放在model中对应的数据暂存到
HttpSession 中。 - @SessionAttributes只能使用在类定义上。
- @SessionAttributes 除了可以通过属性名指定需要放到会 话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中 例如:
- @SessionAttributes(types=User.class)会将model中所有类型为 User的属性添加到会话中。
- @SessionAttributes(value={“user1”, “user2”}) 会将model中属性名为user1和user2的属性添加到会话中。
- @SessionAttributes(types={User.class, Dept.class}) 会将model中所有类型为 User和Dept的属性添加到会话中。
- @SessionAttributes(value={“user1”,“user2”},types={Dept.class})会将model中属性名为user1和user2以及类型为Dept的属性添加到会话中。
@SessionAttributes(value={"user"})
@Controller
public class UserController {
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
User user = new User("jack","123456");
model.addAttribute("user", user);
return "success";
}
}
user不仅会放到request的attribute中,也会放到session的attribute中
清除方式
public ModelAndView test(SessionStatus status) {
status.setComplete();
...
}
只会删除通过@SessionAttribute保存到session中的参数
注意
这样是不行的,原因猜测:返回试图名,spring mvc又会重新封装一个ModelAndView 对象
@RequestMapping("/model1")
public String model1(ModelAndView modelAndView){
Person p = new Person();
modelAndView.addObject("pp","21312312asa");
modelAndView.setViewName("m");
return "m";
}
六 @ModelAttribute
参考:https://blog.csdn.net/huawuque004/article/details/81586914
具体用法示例
在调用请求方法前,根据参数先在(map)implicitModel 中放一些预设值
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id,
Map<String, Object> maps){
System.out.println("getUser");
if(id != null){
Person p = new Person();
p.setName("zhuyc");
maps.put("person",p);
}
}
@RequestMapping("/mode1")
public String mode1(Person p1){
System.out.println("mode1");
System.out.println(p1.getName());
return "mode1";
}
@RequestMapping("/mode2")
public String mode2(@ModelAttribute("person")Person p1){
System.out.println("mode1");
System.out.println(p1.getName());
return "mode1";
}
注意
- @ModelAttribute修饰的方法会被Springmvc提前执行,运行在每个目标方法之前。
- 匹配模式1:map存入的键需要和目标方法入参类型的第一个字母小写的字符串一致
- 匹配模式2:利用注解ModelAttribute修饰且设置value属性值指向你的map中的键名
在implicitModel 中查找attrName对应的属性值,如果存在,进行利用。如果不存在,则验证当前Handler是否使用了@SessionAttribute进行修饰类。如果使用了@SessionAttribute,则尝试从HttpSession中获取attrName所对应的值,若Session中没有所对应的值,则会抛出异常。【这也是SessionAttribute与ModelAttribute共同使用时造成的一个常见问题】,如果当前Handler没有使用@SessionAttribute修饰类,且@SessionAttribute中没有使用value值指定的key和attrName相匹配,则通过反射机制进行创建POJO 对象
1.取不到就会new一个新的POJO类(很常见)
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id,
Map<String, Object> maps){
System.out.println("getUser");
if(id != null){
// Person p = new Person();
// p.setName("zhuyc");
// maps.put("person",p);
System.out.println("testput");
}
}
@RequestMapping("/mode1")
public String mode1(Person p1){
System.out.println("mode1");
System.out.println(p1.getName());
return "mode1";
}
=====输出====
getUser
testput
mode1
null
2.抛出异常(先请求mode2)
@SessionAttributes(value={"person"})
@Controller
@RequestMapping("/ma")
public class ModelAttributeDemoController {
@ModelAttribute//这个方法没有影响结论
public void getUser(@RequestParam(value="id",required=false) Integer id,
Map<String, Object> maps){
System.out.println("getUser");
if(id != null){
// Person p = new Person();
// p.setName("zhuyc");
// maps.put("person",p);
System.out.println("testput");
}
}
@ResponseBody
@RequestMapping("/mode2")
public String mode2(@ModelAttribute("person")Person p1){
System.out.println("mode2");
System.out.println(p1.getName());
return "mode1";
}
@RequestMapping("/model1")
public ModelAndView model1(ModelAndView modelAndView){
Person p = new Person();
p.setName("asdsadasdas");
modelAndView.addObject("person",p);
modelAndView.setViewName("m");
return modelAndView;
}
====结果报错,但先执行model1就没关系了====
org.springframework.web.HttpSessionRequiredException: Expected session attribute 'person'
org.springframework.web.method.annotation.ModelFactory.initModel(ModelFactory.java:115)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:810)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
3.一旦类上的@SessionAttributes
的value值和@ModelAttribute
不一样,则没有该值也不会报错
@SessionAttributes(value={"person1"})
@Controller
@RequestMapping("/ma")
public class ModelAttributeDemoController {
...
@ResponseBody
@RequestMapping("/mode2")
public String mode2(@ModelAttribute("person")Person p1){
System.out.println("mode2");
System.out.println(p1.getName());
return "mode1";
}
七 异常处理
Spring MVC 通过 HandlerExceptionResolver 处理程序 的异常,包括 Handler 映射、数据绑定以及目标方法执行 时发生的异常。
ExceptionHandlerExceptionResolver
HandlerExceptionResolver 的一个实现
- 在
@ExceptionHandler
方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象 - @ExceptionHandler 方法的入参中
不能传入 Map
. 若希望把异常信息传导页面上, 需要使用ModelAndView
作为返回值 - @ExceptionHandler 方法标记的异常有优先级的问题. 越
精确
越优先。 - @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常, 则将去
@ControllerAdvice
标记的类中查找 @ExceptionHandler 标记的方法来处理异常.
@Controller
public class SpringMVCTest {
...
@ExceptionHandler({RuntimeException.class})
public ModelAndView handleArithmeticException2(Exception ex){
System.out.println("[出异常了]: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
}
ResponseStatusExceptionResolver
在异常及异常父类中找到 @ResponseStatus 注解,然 后使用这个注解的属性进行处理。
用法:
- 定义一个
@ResponseStatus
注解修饰的异常类 。
若在处理器方法中抛出了上述异常: 若ExceptionHandlerExceptionResolver 不解析述异常。由于触发的异常 UnauthorizedException 带有@ResponseStatus 注解。因此会被ResponseStatusExceptionResolver 解析到
@ResponseStatus(value=HttpStatus.FORBIDDEN, reason="用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException{
private static final long serialVersionUID = 1L;
}
- 修饰在方法上,方法会执行,但返回结果时有注解决定的状态码和reason信息
DefaultHandlerExceptionResolver
对一些特殊的异常进行处理,比 如NoSuchRequestHandlingMethodException、HttpReques tMethodNotSupportedException、HttpMediaTypeNotSuppo rtedException、HttpMediaTypeNotAcceptableException 等
SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为 视图名,即发生异常时使用对应的视图报告异常
八 ResponseStatus
Spring MVC应用中,通过使用注解@ResponseStatus,我们可以设置HTTP响应的状态。
具体的使用方式这里我们介绍两种 :
用在控制器方法上
用在异常类上
用在控制器方法上(status+reason)
不管该方法是不是发生了异常,将@ResponseStatus注解加在目标方法上,一定会抛出异常。但是如果方法执行过程中没有发生异常的话,方法会正常执行完毕。
@ResponseBody
@ResponseStatus(reason = "测试方法上的@ResponseStatus", value = HttpStatus.BAD_REQUEST)
@RequestMapping("/method")
public String method() {
System.out.println("mmm");
return "method";
}
因为抛出异常了,而且没有配置异常处理所以没有返回json数据
image.png用在异常类上
@ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "这是一个测试ResponseStatus的异常")
public class TestException extends RuntimeException{
}
====
@ResponseBody
@RequestMapping("/cls")
public String cls(int i) {
System.out.println("clssdds");
if(i == 0)
throw new TestException();
return "cls";
}
效果
用在异常处理器方法上
这个效果就是设置返回的响应状态
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
@ExceptionHandler
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handle(Exception exception) {
System.out.println("h1");
if(exception instanceof ConstraintViolationException){
ConstraintViolationException exs = (ConstraintViolationException) exception;
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
for (ConstraintViolation<?> item : violations) {
/**打印验证不通过的信息*/
System.out.println("global: "+item.getMessage());
}
}
return "bad request, " ;
}
}
网友评论