美文网首页
(三)注解、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