美文网首页
(三)注解、restful

(三)注解、restful

作者: guideEmotion | 来源:发表于2019-06-15 22:18 被阅读0次

一 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 除了可以通过属性名指定需要放到会 话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中 例如:
    1. @SessionAttributes(types=User.class)会将model中所有类型为 User的属性添加到会话中。
    2. @SessionAttributes(value={“user1”, “user2”}) 会将model中属性名为user1和user2的属性添加到会话中。
    3. @SessionAttributes(types={User.class, Dept.class}) 会将model中所有类型为 User和Dept的属性添加到会话中。
    4. @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 中放一些预设值

image.png

    @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";
    }

注意

  1. @ModelAttribute修饰的方法会被Springmvc提前执行,运行在每个目标方法之前。
  2. 匹配模式1:map存入的键需要和目标方法入参类型的第一个字母小写的字符串一致
  3. 匹配模式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 &#39;person&#39;
    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 的一个实现

  1. @ExceptionHandler方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象
  2. @ExceptionHandler 方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView作为返回值
  3. @ExceptionHandler 方法标记的异常有优先级的问题. 越精确越优先。
  4. @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 注解,然 后使用这个注解的属性进行处理。

用法:

  1. 定义一个 @ResponseStatus 注解修饰的异常类 。
    若在处理器方法中抛出了上述异常: 若ExceptionHandlerExceptionResolver 不解析述异常。由于触发的异常 UnauthorizedException 带有@ResponseStatus 注解。因此会被ResponseStatusExceptionResolver 解析到
    @ResponseStatus(value=HttpStatus.FORBIDDEN, reason="用户名和密码不匹配!")
    public class UserNameNotMatchPasswordException extends RuntimeException{
        private static final long serialVersionUID = 1L;
        
    }
  1. 修饰在方法上,方法会执行,但返回结果时有注解决定的状态码和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";
    }

效果

image.png

用在异常处理器方法上

这个效果就是设置返回的响应状态

@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, " ;
    }


}

改变请求的响应状态

参考

  1. @RequestMapping用法详解
  2. @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  3. https://blog.csdn.net/andy_zhang2007/article/details/88680628

相关文章

网友评论

      本文标题:(三)注解、restful

      本文链接:https://www.haomeiwen.com/subject/fwycfctx.html